From 4622fa4b6608481c561c037b8e423d2ec39ff34d Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 1 Feb 2021 12:48:33 +0100 Subject: [PATCH 01/18] Fonts: Fixed CalcTextSize() width rounding so it behaves more like a ceil. (#3776) his is in order for text wrapping to have enough space when provided width precisely calculated with CalcTextSize().x. Amend 7b0bf230. Note that the rounding of either positions and widths are technically undesirable (e.g. #3437, #791) but variety of code is currently on it so we are first fixing current behavior before we'll eventually change it. --- docs/CHANGELOG.txt | 4 ++++ imgui.cpp | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index ee7e3f28f..de1d3cf91 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,6 +53,10 @@ Other Changes: other than compiling misc/freetype/imgui_freetype.cpp and linking with FreeType. - Use '#define IMGUI_ENABLE_STB_TRUETYPE' if you somehow need the stb_truetype rasterizer to be compiled in along with the FreeType one, otherwise it is enabled by default. +- Fonts: Fixed CalcTextSize() width rounding so it behaves more like a ceil. This is in order for text wrapping + to have enough space when provided width precisely calculated with CalcTextSize().x. (#3776) + Note that the rounding of either positions and widths are technically undesirable (e.g. #3437, #791) but + variety of code is currently on it so we are first fixing current behavior before we'll eventually chhnge it. - ImDrawList: Fixed AddCircle()/AddCircleFilled() with (rad > 0.0f && rad < 1.0f && num_segments == 0). (#3738) Would lead to a buffer read overflow. - Backends: Win32: Dynamically loading XInput DLL instead of linking with it, facilite compiling with diff --git a/imgui.cpp b/imgui.cpp index 380df5702..5f32a2cea 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4410,7 +4410,11 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex ImVec2 text_size = font->CalcTextSizeA(font_size, FLT_MAX, wrap_width, text, text_display_end, NULL); // Round - text_size.x = IM_FLOOR(text_size.x + 0.95f); + // FIXME: This has been here since Dec 2015 (7b0bf230) but down the line we want this out. + // FIXME: Investigate using ceilf or e.g. + // - https://git.musl-libc.org/cgit/musl/tree/src/math/ceilf.c + // - https://embarkstudios.github.io/rust-gpu/api/src/libm/math/ceilf.rs.html + text_size.x = IM_FLOOR(text_size.x + 0.99999f); return text_size; } From 24aa6654dfe1c58c4d8b70c0df73593e8d92f758 Mon Sep 17 00:00:00 2001 From: Petr Shurgalin Date: Thu, 28 Jan 2021 16:57:37 +0100 Subject: [PATCH 02/18] imgui_freetype: add support for colored glyphs with ImGuiFreeTypeBuilderFlags_LoadColor (#3369) (squashed 4 commits) --- imgui_draw.cpp | 61 +++++++++++++++++++--- misc/freetype/imgui_freetype.cpp | 89 ++++++++++++++++++++++++++------ misc/freetype/imgui_freetype.h | 3 +- 3 files changed, 129 insertions(+), 24 deletions(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index ad106c3c0..b3e8de317 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -2457,6 +2457,16 @@ void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : 0x00; } +void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value) +{ + IM_ASSERT(x >= 0 && x + w <= atlas->TexWidth); + IM_ASSERT(y >= 0 && y + h <= atlas->TexHeight); + unsigned int* out_pixel = atlas->TexPixelsRGBA32 + x + (y * atlas->TexWidth); + for (int off_y = 0; off_y < h; off_y++, out_pixel += atlas->TexWidth, in_str += w) + for (int off_x = 0; off_x < w; off_x++) + out_pixel[off_x] = (in_str[off_x] == in_marker_char) ? in_marker_pixel_value : IM_COL32_BLACK_TRANS; +} + static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) { ImFontAtlasCustomRect* r = atlas->GetCustomRectByIndex(atlas->PackIdMouseCursors); @@ -2469,15 +2479,30 @@ static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas) IM_ASSERT(r->Width == FONT_ATLAS_DEFAULT_TEX_DATA_W * 2 + 1 && r->Height == FONT_ATLAS_DEFAULT_TEX_DATA_H); const int x_for_white = r->X; const int x_for_black = r->X + FONT_ATLAS_DEFAULT_TEX_DATA_W + 1; - ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF); - ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF); + if (atlas->TexPixelsAlpha8 != NULL) + { + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', 0xFF); + ImFontAtlasBuildRender8bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', 0xFF); + } + else + { + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_white, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, '.', IM_COL32_WHITE); + ImFontAtlasBuildRender32bppRectFromString(atlas, x_for_black, r->Y, FONT_ATLAS_DEFAULT_TEX_DATA_W, FONT_ATLAS_DEFAULT_TEX_DATA_H, FONT_ATLAS_DEFAULT_TEX_DATA_PIXELS, 'X', IM_COL32_WHITE); + } } else { // Render 4 white pixels IM_ASSERT(r->Width == 2 && r->Height == 2); const int offset = (int)r->X + (int)r->Y * w; - atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + if (atlas->TexPixelsAlpha8 != NULL) + { + atlas->TexPixelsAlpha8[offset] = atlas->TexPixelsAlpha8[offset + 1] = atlas->TexPixelsAlpha8[offset + w] = atlas->TexPixelsAlpha8[offset + w + 1] = 0xFF; + } + else + { + atlas->TexPixelsRGBA32[offset] = atlas->TexPixelsRGBA32[offset + 1] = atlas->TexPixelsRGBA32[offset + w] = atlas->TexPixelsRGBA32[offset + w + 1] = IM_COL32_WHITE; + } } atlas->TexUvWhitePixel = ImVec2((r->X + 0.5f) * atlas->TexUvScale.x, (r->Y + 0.5f) * atlas->TexUvScale.y); } @@ -2500,10 +2525,30 @@ static void ImFontAtlasBuildRenderLinesTexData(ImFontAtlas* atlas) // Write each slice IM_ASSERT(pad_left + line_width + pad_right == r->Width && y < r->Height); // Make sure we're inside the texture bounds before we start writing pixels - unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; - memset(write_ptr, 0x00, pad_left); - memset(write_ptr + pad_left, 0xFF, line_width); - memset(write_ptr + pad_left + line_width, 0x00, pad_right); + if (atlas->TexPixelsAlpha8 != NULL) + { + unsigned char* write_ptr = &atlas->TexPixelsAlpha8[r->X + ((r->Y + y) * atlas->TexWidth)]; + for (unsigned int i = 0; i < pad_left; i++) + *(write_ptr + i) = 0x00; + + for (unsigned int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = 0xFF; + + for (unsigned int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = 0x00; + } + else + { + unsigned int* write_ptr = &atlas->TexPixelsRGBA32[r->X + ((r->Y + y) * atlas->TexWidth)]; + for (unsigned int i = 0; i < pad_left; i++) + *(write_ptr + i) = IM_COL32_BLACK_TRANS; + + for (unsigned int i = 0; i < line_width; i++) + *(write_ptr + pad_left + i) = IM_COL32_WHITE; + + for (unsigned int i = 0; i < pad_right; i++) + *(write_ptr + pad_left + line_width + i) = IM_COL32_BLACK_TRANS; + } // Calculate UVs for this line ImVec2 uv0 = ImVec2((float)(r->X + pad_left - 1), (float)(r->Y + y)) * atlas->TexUvScale; @@ -2538,7 +2583,7 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas) void ImFontAtlasBuildFinish(ImFontAtlas* atlas) { // Render into our custom data blocks - IM_ASSERT(atlas->TexPixelsAlpha8 != NULL); + IM_ASSERT(atlas->TexPixelsAlpha8 != NULL || atlas->TexPixelsRGBA32 != NULL); ImFontAtlasBuildRenderDefaultTexData(atlas); ImFontAtlasBuildRenderLinesTexData(atlas); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index e96559bf0..97646a414 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -126,7 +126,7 @@ namespace void SetPixelHeight(int pixel_height); // Change font pixel size. All following calls to RasterizeGlyph() will use this size const FT_Glyph_Metrics* LoadGlyph(uint32_t in_codepoint); const FT_Bitmap* RenderGlyphAndGetInfo(GlyphInfo* out_glyph_info); - void BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL); + void BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table = NULL); ~FreeTypeFont() { CloseFont(); } // [Internals] @@ -173,6 +173,9 @@ namespace else RenderMode = FT_RENDER_MODE_NORMAL; + if (UserFlags & ImGuiFreeTypeBuilderFlags_LoadColor) + LoadFlags |= FT_LOAD_COLOR; + return true; } @@ -253,7 +256,7 @@ namespace return ft_bitmap; } - void FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint8_t* dst, uint32_t dst_pitch, unsigned char* multiply_table) + void FreeTypeFont::BlitGlyph(const FT_Bitmap* ft_bitmap, uint32_t* dst, uint32_t dst_pitch, unsigned char* multiply_table) { IM_ASSERT(ft_bitmap != NULL); const uint32_t w = ft_bitmap->width; @@ -268,13 +271,18 @@ namespace if (multiply_table == NULL) { for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) - memcpy(dst, src, w); + { + for (uint32_t x = 0; x < w; x++) + dst[x] = IM_COL32(255, 255, 255, src[x]); + } } else { for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + { for (uint32_t x = 0; x < w; x++) - dst[x] = multiply_table[src[x]]; + dst[x] = IM_COL32(255, 255, 255, multiply_table[src[x]]); + } } break; } @@ -290,11 +298,43 @@ namespace { if ((x & 7) == 0) bits = *bits_ptr++; - dst[x] = (bits & 0x80) ? color1 : color0; + dst[x] = IM_COL32(255, 255, 255, (bits & 0x80) ? color1 : color0); } } break; } + case FT_PIXEL_MODE_BGRA: + { + #define DE_MULTIPLY(color, alpha) (ImU32)(255.0f * (float)color / (float)alpha + 0.5f) + + if (multiply_table == NULL) + { + for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + { + for (uint32_t x = 0; x < w; x++) + dst[x] = IM_COL32( + DE_MULTIPLY(src[x * 4 + 2], src[x * 4 + 3]), + DE_MULTIPLY(src[x * 4 + 1], src[x * 4 + 3]), + DE_MULTIPLY(src[x * 4], src[x * 4 + 3]), + src[x * 4 + 3]); + } + } + else + { + for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) + { + for (uint32_t x = 0; x < w; x++) + dst[x] = IM_COL32( + multiply_table[DE_MULTIPLY(src[x * 4 + 2], src[x * 4 + 3])], + multiply_table[DE_MULTIPLY(src[x * 4 + 1], src[x * 4 + 3])], + multiply_table[DE_MULTIPLY(src[x * 4], src[x * 4 + 3])], + multiply_table[src[x * 4 + 3]]); + } + } + + #undef DE_MULTIPLY + break; + } default: IM_ASSERT(0 && "FreeTypeFont::BlitGlyph(): Unknown bitmap pixel mode!"); } @@ -318,7 +358,7 @@ struct ImFontBuildSrcGlyphFT { GlyphInfo Info; uint32_t Codepoint; - unsigned char* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array + unsigned int* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array }; struct ImFontBuildSrcDataFT @@ -498,7 +538,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u IM_ASSERT(ft_bitmap); // Allocate new temporary chunk if needed - const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height; + const int bitmap_size_in_bytes = src_glyph.Info.Width * src_glyph.Info.Height * 4; if (buf_bitmap_current_used_bytes + bitmap_size_in_bytes > BITMAP_BUFFERS_CHUNK_SIZE) { buf_bitmap_current_used_bytes = 0; @@ -506,9 +546,9 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u } // Blit rasterized pixels to our temporary buffer and keep a pointer to it. - src_glyph.BitmapData = buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes; + src_glyph.BitmapData = (unsigned int*)(buf_bitmap_buffers.back() + buf_bitmap_current_used_bytes); buf_bitmap_current_used_bytes += bitmap_size_in_bytes; - src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width * 1, multiply_enabled ? multiply_table : NULL); + src_tmp.Font.BlitGlyph(ft_bitmap, src_glyph.BitmapData, src_glyph.Info.Width, multiply_enabled ? multiply_table : NULL); src_tmp.Rects[glyph_i].w = (stbrp_coord)(src_glyph.Info.Width + padding); src_tmp.Rects[glyph_i].h = (stbrp_coord)(src_glyph.Info.Height + padding); @@ -555,8 +595,16 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u // 7. Allocate texture atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); - atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight); - memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); + if (extra_flags & ImGuiFreeTypeBuilderFlags_LoadColor) + { + atlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight * 4); + memset(atlas->TexPixelsRGBA32, 0, atlas->TexWidth * atlas->TexHeight * 4); + } + else + { + atlas->TexPixelsAlpha8 = (unsigned char*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight); + memset(atlas->TexPixelsAlpha8, 0, atlas->TexWidth * atlas->TexHeight); + } // 8. Copy rasterized font characters back into the main texture // 9. Setup ImFont and glyphs for runtime @@ -596,10 +644,21 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u // 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; - unsigned char* blit_src = src_glyph.BitmapData; - unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx; - for (int y = info.Height; y > 0; y--, blit_dst += blit_dst_stride, blit_src += blit_src_stride) - memcpy(blit_dst, blit_src, blit_src_stride); + unsigned int* blit_src = src_glyph.BitmapData; + if (atlas->TexPixelsAlpha8 != NULL) + { + unsigned char* blit_dst = atlas->TexPixelsAlpha8 + (ty * blit_dst_stride) + tx; + for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride) + for (int x = 0; x < info.Width; x++) + blit_dst[x] = (unsigned char)((blit_src[x] >> IM_COL32_A_SHIFT) & 0xFF); + } + else + { + unsigned int* blit_dst = atlas->TexPixelsRGBA32 + (ty * blit_dst_stride) + tx; + for (int y = 0; y < info.Height; y++, blit_dst += blit_dst_stride, blit_src += blit_src_stride) + for (int x = 0; x < info.Width; x++) + blit_dst[x] = blit_src[x]; + } // Register glyph float x0 = info.OffsetX + font_off_x; diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index 2b953f2f2..eb31ed2d9 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -25,7 +25,8 @@ enum ImGuiFreeTypeBuilderFlags ImGuiFreeTypeBuilderFlags_MonoHinting = 1 << 4, // Strong hinting algorithm that should only be used for monochrome output. ImGuiFreeTypeBuilderFlags_Bold = 1 << 5, // Styling: Should we artificially embolden the font? ImGuiFreeTypeBuilderFlags_Oblique = 1 << 6, // Styling: Should we slant the font, emulating italic style? - ImGuiFreeTypeBuilderFlags_Monochrome = 1 << 7 // Disable anti-aliasing. Combine this with MonoHinting for best results! + ImGuiFreeTypeBuilderFlags_Monochrome = 1 << 7, // Disable anti-aliasing. Combine this with MonoHinting for best results! + ImGuiFreeTypeBuilderFlags_LoadColor = 1 << 8 // Enable FreeType color-layered glyphs }; namespace ImGuiFreeType From 24be26e00ef23e894718bf2cfd32532852f03d72 Mon Sep 17 00:00:00 2001 From: ocornut Date: Thu, 28 Jan 2021 17:26:41 +0100 Subject: [PATCH 03/18] imgui_freetype: Add support for colored glyphs. Font: add support for untinted glyphs (#3369) Amend 9499afd with missing static inline. --- docs/CHANGELOG.txt | 5 +++- imgui.h | 5 ++-- imgui_draw.cpp | 16 +++++++++--- imgui_internal.h | 3 ++- misc/freetype/imgui_freetype.cpp | 43 ++++++++++++++++---------------- misc/freetype/imgui_freetype.h | 2 +- 6 files changed, 44 insertions(+), 30 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index de1d3cf91..012874c88 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -53,10 +53,13 @@ Other Changes: other than compiling misc/freetype/imgui_freetype.cpp and linking with FreeType. - Use '#define IMGUI_ENABLE_STB_TRUETYPE' if you somehow need the stb_truetype rasterizer to be compiled in along with the FreeType one, otherwise it is enabled by default. +- imgui_freetype: Added support for colored glyphs as supported by Freetype 2.10+ (for .ttf using CPAL/COLR + tables only). Enable the ImGuiFreeTypeBuilderFlags_LoadColor on a given font. Atlas always output directly + as RGBA8 in this situation. Likely to make sense with IMGUI_USE_WCHAR32. (#3369) [@pshurgal] - Fonts: Fixed CalcTextSize() width rounding so it behaves more like a ceil. This is in order for text wrapping to have enough space when provided width precisely calculated with CalcTextSize().x. (#3776) Note that the rounding of either positions and widths are technically undesirable (e.g. #3437, #791) but - variety of code is currently on it so we are first fixing current behavior before we'll eventually chhnge it. + variety of code is currently on it so we are first fixing current behavior before we'll eventually change it. - ImDrawList: Fixed AddCircle()/AddCircleFilled() with (rad > 0.0f && rad < 1.0f && num_segments == 0). (#3738) Would lead to a buffer read overflow. - Backends: Win32: Dynamically loading XInput DLL instead of linking with it, facilite compiling with diff --git a/imgui.h b/imgui.h index 6bfe7532f..61937da69 100644 --- a/imgui.h +++ b/imgui.h @@ -2504,8 +2504,9 @@ struct ImFontConfig // (Note: some language parsers may fail to convert the 31+1 bitfield members, in this case maybe drop store a single u32 or we can rework this) struct ImFontGlyph { - unsigned int Codepoint : 31; // 0x0000..0xFFFF - unsigned int Visible : 1; // Flag to allow early out when rendering + unsigned int Colored : 1; // Flag to indicate glyph is colored and should generally ignore tinting (make it usable with no shift on little-endian as this is used in loops) + unsigned int Visible : 1; // Flag to indicate glyph has no visible pixels (e.g. space). Allow early out when rendering. + unsigned int Codepoint : 30; // 0x0000..0x10FFFF float AdvanceX; // Distance to next character (= data from font + ImFontConfig::GlyphExtraSpacing.x baked in) float X0, Y0, X1, Y1; // Glyph corners float U0, V0, U1, V1; // Texture coordinates diff --git a/imgui_draw.cpp b/imgui_draw.cpp index b3e8de317..213ac4478 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -3065,6 +3065,7 @@ void ImFont::AddGlyph(const ImFontConfig* cfg, ImWchar codepoint, float x0, floa ImFontGlyph& glyph = Glyphs.back(); glyph.Codepoint = (unsigned int)codepoint; glyph.Visible = (x0 != x1) && (y0 != y1); + glyph.Colored = false; glyph.X0 = x0; glyph.Y0 = y0; glyph.X1 = x1; @@ -3315,6 +3316,8 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col const ImFontGlyph* glyph = FindGlyph(c); if (!glyph || !glyph->Visible) return; + if (glyph->Colored) + col |= ~IM_COL32_A_MASK; float scale = (size >= 0.0f) ? (size / FontSize) : 1.0f; pos.x = IM_FLOOR(pos.x); pos.y = IM_FLOOR(pos.y); @@ -3377,6 +3380,8 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col ImDrawIdx* idx_write = draw_list->_IdxWritePtr; unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx; + const ImU32 col_untinted = col | ~IM_COL32_A_MASK; + while (s < text_end) { if (word_wrap_enabled) @@ -3482,14 +3487,17 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col } } + // Support for untinted glyphs + ImU32 glyph_col = glyph->Colored ? col_untinted : col; + // We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here: { idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2); idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3); - vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; - vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; - vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; - vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; + vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1; + vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1; + vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2; + vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2; vtx_write += 4; vtx_current_idx += 4; idx_write += 6; diff --git a/imgui_internal.h b/imgui_internal.h index 1c961617a..38e3588de 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2509,7 +2509,8 @@ IMGUI_API void ImFontAtlasBuildInit(ImFontAtlas* atlas); IMGUI_API void ImFontAtlasBuildSetupFont(ImFontAtlas* atlas, ImFont* font, ImFontConfig* font_config, float ascent, float descent); IMGUI_API void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opaque); IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas); -IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int atlas_x, int atlas_y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value); +IMGUI_API void ImFontAtlasBuildRender8bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned char in_marker_pixel_value); +IMGUI_API void ImFontAtlasBuildRender32bppRectFromString(ImFontAtlas* atlas, int x, int y, int w, int h, const char* in_str, char in_marker_char, unsigned int in_marker_pixel_value); IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor); IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride); diff --git a/misc/freetype/imgui_freetype.cpp b/misc/freetype/imgui_freetype.cpp index 97646a414..db1b68e53 100644 --- a/misc/freetype/imgui_freetype.cpp +++ b/misc/freetype/imgui_freetype.cpp @@ -6,6 +6,7 @@ // CHANGELOG // (minor and older changes stripped away, please see git history for details) +// 2021/01/28: added support for color-layered glyphs via ImGuiFreeTypeBuilderFlags_LoadColor (require Freetype 2.10+). // 2021/01/26: simplified integration by using '#define IMGUI_ENABLE_FREETYPE'. // renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. removed ImGuiFreeType::BuildFontAtlas(). // 2020/06/04: fix for rare case where FT_Get_Char_Index() succeed but FT_Load_Glyph() fails. @@ -96,7 +97,7 @@ namespace // | | // |------------- advanceX ----------->| - /// A structure that describe a glyph. + // A structure that describe a glyph. struct GlyphInfo { int Width; // Glyph's width in pixels. @@ -104,6 +105,7 @@ namespace FT_Int OffsetX; // The distance from the origin ("pen position") to the left of the glyph. FT_Int OffsetY; // The distance from the origin to the top of the glyph. This is usually a value < 0. float AdvanceX; // The distance from the origin to the origin of the next glyph. This is usually a value > 0. + bool IsColored; }; // Font parameters and metrics. @@ -252,6 +254,7 @@ namespace out_glyph_info->OffsetX = Face->glyph->bitmap_left; out_glyph_info->OffsetY = -Face->glyph->bitmap_top; out_glyph_info->AdvanceX = (float)FT_CEIL(slot->advance.x); + out_glyph_info->IsColored = (ft_bitmap->pixel_mode == FT_PIXEL_MODE_BGRA); return ft_bitmap; } @@ -271,18 +274,14 @@ namespace if (multiply_table == NULL) { for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) - { for (uint32_t x = 0; x < w; x++) dst[x] = IM_COL32(255, 255, 255, src[x]); - } } else { for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) - { for (uint32_t x = 0; x < w; x++) dst[x] = IM_COL32(255, 255, 255, multiply_table[src[x]]); - } } break; } @@ -305,33 +304,28 @@ namespace } case FT_PIXEL_MODE_BGRA: { + // FIXME: Converting pre-multiplied alpha to straight. Doesn't smell good. #define DE_MULTIPLY(color, alpha) (ImU32)(255.0f * (float)color / (float)alpha + 0.5f) - if (multiply_table == NULL) { for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) - { for (uint32_t x = 0; x < w; x++) - dst[x] = IM_COL32( - DE_MULTIPLY(src[x * 4 + 2], src[x * 4 + 3]), - DE_MULTIPLY(src[x * 4 + 1], src[x * 4 + 3]), - DE_MULTIPLY(src[x * 4], src[x * 4 + 3]), - src[x * 4 + 3]); - } + { + uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3]; + dst[x] = IM_COL32(DE_MULTIPLY(r, a), DE_MULTIPLY(g, a), DE_MULTIPLY(b, a), a); + } } else { for (uint32_t y = 0; y < h; y++, src += src_pitch, dst += dst_pitch) { for (uint32_t x = 0; x < w; x++) - dst[x] = IM_COL32( - multiply_table[DE_MULTIPLY(src[x * 4 + 2], src[x * 4 + 3])], - multiply_table[DE_MULTIPLY(src[x * 4 + 1], src[x * 4 + 3])], - multiply_table[DE_MULTIPLY(src[x * 4], src[x * 4 + 3])], - multiply_table[src[x * 4 + 3]]); + { + uint8_t r = src[x * 4 + 2], g = src[x * 4 + 1], b = src[x * 4], a = src[x * 4 + 3]; + dst[x] = IM_COL32(multiply_table[DE_MULTIPLY(r, a)], multiply_table[DE_MULTIPLY(g, a)], multiply_table[DE_MULTIPLY(b, a)], multiply_table[a]); + } } } - #undef DE_MULTIPLY break; } @@ -359,6 +353,8 @@ struct ImFontBuildSrcGlyphFT GlyphInfo Info; uint32_t Codepoint; unsigned int* BitmapData; // Point within one of the dst_tmp_bitmap_buffers[] array + + ImFontBuildSrcGlyphFT() { memset(this, 0, sizeof(*this)); } }; struct ImFontBuildSrcDataFT @@ -396,6 +392,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u atlas->ClearTexData(); // Temporary storage for building + bool src_load_color = false; ImVector src_tmp_array; ImVector dst_tmp_array; src_tmp_array.resize(atlas->ConfigData.Size); @@ -425,6 +422,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u return false; // Measure highest codepoints + src_load_color |= (cfg.FontBuilderFlags & ImGuiFreeTypeBuilderFlags_LoadColor) != 0; ImFontBuildDstDataFT& dst_tmp = dst_tmp_array[src_tmp.DstIndex]; src_tmp.SrcRanges = cfg.GlyphRanges ? cfg.GlyphRanges : atlas->GetGlyphRangesDefault(); for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2) @@ -476,7 +474,6 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u if (entries_32 & ((ImU32)1 << bit_n)) { ImFontBuildSrcGlyphFT src_glyph; - memset(&src_glyph, 0, sizeof(src_glyph)); src_glyph.Codepoint = (ImWchar)(((it - it_begin) << 5) + bit_n); //src_glyph.GlyphIndex = 0; // FIXME-OPT: We had this info in the previous step and lost it.. src_tmp.GlyphsList.push_back(src_glyph); @@ -595,7 +592,7 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u // 7. Allocate texture atlas->TexHeight = (atlas->Flags & ImFontAtlasFlags_NoPowerOfTwoHeight) ? (atlas->TexHeight + 1) : ImUpperPowerOfTwo(atlas->TexHeight); atlas->TexUvScale = ImVec2(1.0f / atlas->TexWidth, 1.0f / atlas->TexHeight); - if (extra_flags & ImGuiFreeTypeBuilderFlags_LoadColor) + if (src_load_color) { atlas->TexPixelsRGBA32 = (unsigned int*)IM_ALLOC(atlas->TexWidth * atlas->TexHeight * 4); memset(atlas->TexPixelsRGBA32, 0, atlas->TexWidth * atlas->TexHeight * 4); @@ -670,6 +667,10 @@ bool ImFontAtlasBuildWithFreeTypeEx(FT_Library ft_library, ImFontAtlas* atlas, u 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); + + IM_ASSERT(dst_font->Glyphs.back().Codepoint == src_glyph.Codepoint); + if (src_glyph.Info.IsColored) + dst_font->Glyphs.back().Colored = true; } src_tmp.Rects = NULL; diff --git a/misc/freetype/imgui_freetype.h b/misc/freetype/imgui_freetype.h index eb31ed2d9..d570f83a9 100644 --- a/misc/freetype/imgui_freetype.h +++ b/misc/freetype/imgui_freetype.h @@ -44,6 +44,6 @@ namespace ImGuiFreeType // Obsolete names (will be removed soon) // Prefer using '#define IMGUI_ENABLE_FREETYPE' #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS - bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontBuilderFlags = flags; return atlas->Build(); } + static inline bool BuildFontAtlas(ImFontAtlas* atlas, unsigned int flags = 0) { atlas->FontBuilderIO = GetBuilderForFreeType(); atlas->FontBuilderFlags = flags; return atlas->Build(); } #endif } From 4dec43616133f1477c302b96849172b2764ccf4a Mon Sep 17 00:00:00 2001 From: Erwin Coumans Date: Sun, 31 Jan 2021 10:26:50 -0800 Subject: [PATCH 04/18] SliderInt: Fixed click/drag when v_min==v_max from setting the value to zero. (#3774) --- docs/CHANGELOG.txt | 2 ++ imgui_widgets.cpp | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 012874c88..6042a666b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -48,6 +48,8 @@ Other Changes: - Tables: Fixed PopItemWidth() or multi-components items not restoring per-colum ItemWidth correctly. (#3760) - Window: Fixed minor title bar text clipping issue when FramePadding is small/zero and there are no close button in the window. (#3731) +- SliderInt: Fixed click/drag when v_min==v_max from setting the value to zero. (#3774) [@erwincoumans] + Would also repro with DragFloat() when using ImGuiSliderFlags_Logarithmic with v_min==v_max. - imgui_freetype: Facilitated using FreeType integration: [@Xipiryon, @ocornut] - Use '#define IMGUI_ENABLE_FREETYPE' in imconfig.h should make it work with no other modifications other than compiling misc/freetype/imgui_freetype.cpp and linking with FreeType. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index b765701fd..81f16d647 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -2589,7 +2589,7 @@ template TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type, float t, TYPE v_min, TYPE v_max, bool is_logarithmic, float logarithmic_zero_epsilon, float zero_deadzone_halfsize) { if (v_min == v_max) - return (TYPE)0.0f; + return v_min; const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); TYPE result; From 9d576a96a531cb4591702ca239f5937f188e7b5b Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 1 Feb 2021 17:35:29 +0100 Subject: [PATCH 05/18] Tables: added internal TableSetColumnEnabled() helper. Comments. --- docs/FONTS.md | 3 ++- docs/README.md | 7 ++++--- imgui.h | 4 ++-- imgui_internal.h | 1 + imgui_tables.cpp | 15 +++++++++++++++ 5 files changed, 24 insertions(+), 6 deletions(-) diff --git a/docs/FONTS.md b/docs/FONTS.md index 54b7c295d..62815b82f 100644 --- a/docs/FONTS.md +++ b/docs/FONTS.md @@ -153,7 +153,8 @@ Some solutions: 1. Reduce glyphs ranges by calculating them from source localization data. You can use the `ImFontGlyphRangesBuilder` for this purpose, this will be the biggest win! -2. You may reduce oversampling, e.g. `font_config.OversampleH = font_config.OversampleV = 1`, this will largely reduce your texture size. +2. You may reduce oversampling, e.g. `font_config.OversampleH = 2`, this will largely reduce your texture size. + Note that while OversampleH = 2 looks visibly very close to 3 in most situations, with OversampleH = 1 the quality drop will be noticeable. 3. Set `io.Fonts.TexDesiredWidth` to specify a texture width to minimize texture height (see comment in `ImFontAtlas::Build()` function). 4. Set `io.Fonts.Flags |= ImFontAtlasFlags_NoPowerOfTwoHeight;` to disable rounding the texture height to the next power of two. 5. Read about oversampling [here](https://github.com/nothings/stb/blob/master/tests/oversample). diff --git a/docs/README.md b/docs/README.md index 7c8ea3603..c3d195ca7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -194,15 +194,16 @@ See [Sponsors](https://github.com/ocornut/imgui/wiki/Sponsors) page. Sponsors -------- -Ongoing Dear ImGui development is financially supported by users and private sponsors, recently: +Ongoing Dear ImGui development is currently financially supported by users and private sponsors: *Platinum-chocolate sponsors* - [Blizzard](https://careers.blizzard.com/en-us/openings/engineering/all/all/all/1), [Google](https://github.com/google/filament), [Nvidia](https://developer.nvidia.com/nvidia-omniverse), [Ubisoft](https://montreal.ubisoft.com/en/ubisoft-sponsors-user-interface-library-for-c-dear-imgui/) *Double-chocolate and Salty caramel sponsors* -- [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [Arkane Studios](https://www.arkane-studios.com), [Dotemu](http://www.dotemu.com), [Framefield](http://framefield.com), [Grinding Gear Games](https://www.grindinggear.com), [Hexagon](https://hexagonxalt.com/the-technology/xalt-visualization), [Kylotonn](https://www.kylotonn.com), [Media Molecule](http://www.mediamolecule.com), [Mesh Consultants](https://www.meshconsultants.ca), [Mobigame](http://www.mobigame.net), [Nadeo](https://www.nadeo.com), [Next Level Games](https://www.nextlevelgames.com), [RAD Game Tools](http://www.radgametools.com/), [Supercell](http://www.supercell.com), [Remedy Entertainment](https://www.remedygames.com/), [Unit 2 Games](https://unit2games.com/) +- [Activision](https://careers.activision.com/c/programmingsoftware-engineering-jobs), [Aras Pranckevičius](https://aras-p.info), [Arkane Studios](https://www.arkane-studios.com), [Framefield](http://framefield.com), [Grinding Gear Games](https://www.grindinggear.com), [Kylotonn](https://www.kylotonn.com), [Next Level Games](https://www.nextlevelgames.com), [RAD Game Tools](http://www.radgametools.com/), [Supercell](http://www.supercell.com) -From November 2014 to December 2019, ongoing development has also been financially supported by its users on Patreon and through individual donations. Please see [detailed list of Dear ImGui supporters](https://github.com/ocornut/imgui/wiki/Sponsors). +Please see [detailed list of Dear ImGui supporters](https://github.com/ocornut/imgui/wiki/Sponsors) for past sponsors. +From November 2014 to December 2019, ongoing development has also been financially supported by its users on Patreon and through individual donations. **THANK YOU to all past and present supporters for helping to keep this project alive and thriving!** diff --git a/imgui.h b/imgui.h index 61937da69..a241cfb61 100644 --- a/imgui.h +++ b/imgui.h @@ -2480,8 +2480,8 @@ struct ImFontConfig bool FontDataOwnedByAtlas; // true // TTF/OTF data ownership taken by the container ImFontAtlas (will delete memory itself). int FontNo; // 0 // Index of font within TTF/OTF file float SizePixels; // // Size in pixels for rasterizer (more or less maps to the resulting font height). - int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. - int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. We don't use sub-pixel positions on the Y axis. + int OversampleH; // 3 // Rasterize at higher quality for sub-pixel positioning. Note the difference between 2 and 3 is minimal so you can reduce this to 2 to save memory. Read https://github.com/nothings/stb/blob/master/tests/oversample/README.md for details. + int OversampleV; // 1 // Rasterize at higher quality for sub-pixel positioning. This is not really useful as we don't use sub-pixel positions on the Y axis. bool PixelSnapH; // false // Align every glyph to pixel boundary. Useful e.g. if you are merging a non-pixel aligned font with the default font. If enabled, you can set OversampleH/V to 1. ImVec2 GlyphExtraSpacing; // 0, 0 // Extra spacing (in pixels) between glyphs. Only X axis is supported for now. ImVec2 GlyphOffset; // 0, 0 // Offset all glyphs from this font input. diff --git a/imgui_internal.h b/imgui_internal.h index 38e3588de..ebfcfc2b4 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2318,6 +2318,7 @@ namespace ImGui // Tables: Candidates for public API IMGUI_API void TableOpenContextMenu(int column_n = -1); + IMGUI_API void TableSetColumnEnabled(int column_n, bool enabled); IMGUI_API void TableSetColumnWidth(int column_n, float width); IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. diff --git a/imgui_tables.cpp b/imgui_tables.cpp index ac38185fe..9681e726a 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1460,6 +1460,21 @@ const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n) return &table->ColumnsNames.Buf[column->NameOffset]; } +// For the getter you can use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsEnabled) +void ImGui::TableSetColumnEnabled(int column_n, bool enabled) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL); + if (!table) + return; + if (column_n < 0) + column_n = table->CurrentColumn; + IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount); + ImGuiTableColumn* column = &table->Columns[column_n]; + column->IsEnabledNextFrame = enabled; +} + // We allow querying for an extra column in order to poll the IsHovered state of the right-most section ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n) { From dbaf74d758e54ff188f0779d9f1c9df7aa606156 Mon Sep 17 00:00:00 2001 From: Louis Schnellbach Date: Fri, 15 Jan 2021 11:05:25 +0100 Subject: [PATCH 06/18] Log/Capture: Fix various new line/spacing issue by using same render text position when there are both RenderText and LogRenderedText call in widget code. Also Buttons are now enclosed in bracket --- docs/CHANGELOG.txt | 9 +++++++++ imgui.cpp | 16 +++++++++++++--- imgui_internal.h | 1 + imgui_widgets.cpp | 30 +++++++++++++++++++++--------- 4 files changed, 44 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 6042a666b..58b8f9ec1 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -30,6 +30,15 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! +----------------------------------------------------------------------- + VERSION 1.81 (In Progress) +----------------------------------------------------------------------- + +Other Changes: + +- Log/Capture: Fix various new line/spacing issue by using same render text position when there are both + RenderText and LogRenderedText call in widget code. + Also Buttons are now enclosed in bracket. [@Xipiryon] ----------------------------------------------------------------------- VERSION 1.81 WIP (In Progress) diff --git a/imgui.cpp b/imgui.cpp index 5f32a2cea..f1e05c051 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -7572,7 +7572,7 @@ void ImGui::BeginGroup() window->DC.CursorMaxPos = window->DC.CursorPos; window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); if (g.LogEnabled) - g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return + LogRenderedTextNewLine(); } void ImGui::EndGroup() @@ -7593,7 +7593,7 @@ void ImGui::EndGroup() window->DC.CurrLineSize = group_data.BackupCurrLineSize; window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset; if (g.LogEnabled) - g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return + LogRenderedTextNewLine(); if (!group_data.EmitItem) { @@ -9867,7 +9867,7 @@ void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* if (!text_end) text_end = FindRenderedTextEnd(text, text_end); - const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + 1); + const bool log_new_line = ref_pos && (ref_pos->y > g.LogLinePosY + g.Style.FramePadding.y + 1); if (ref_pos) g.LogLinePosY = ref_pos->y; if (log_new_line) @@ -9895,6 +9895,9 @@ void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* else LogText(" %.*s", char_count, line_start); g.LogLineFirstItem = false; + + if (*line_end == '\n') + LogRenderedTextNewLine(); } else if (log_new_line) { @@ -9909,6 +9912,13 @@ void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* } } +void ImGui::LogRenderedTextNewLine() +{ + // To enforce Log carriage return + ImGuiContext& g = *GImGui; + g.LogLinePosY = -FLT_MAX; +} + // Start logging/capturing text output void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) { diff --git a/imgui_internal.h b/imgui_internal.h index ebfcfc2b4..779c62955 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2392,6 +2392,7 @@ namespace ImGui IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); + IMGUI_API void LogRenderedTextNewLine(); // Render helpers (those functions don't access any ImGui state!) IMGUI_API void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 81f16d647..cea0fb416 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -692,7 +692,13 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); RenderNavHighlight(bb, id); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); - RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); + + ImRect render_text_pos = ImRect(bb.Min + style.FramePadding, bb.Max - style.FramePadding); + if (g.LogEnabled) + LogRenderedText(&render_text_pos.Min, "["); + RenderTextClipped(render_text_pos.Min, render_text_pos.Max ,label, NULL, &label_size, style.ButtonTextAlign, &bb); + if (g.LogEnabled) + LogRenderedText(&render_text_pos.Min, "]"); // Automatically close popups //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) @@ -1097,10 +1103,12 @@ bool ImGui::Checkbox(const char* label, bool* v) RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f); } + + ImVec2 render_text_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); if (g.LogEnabled) - LogRenderedText(&total_bb.Min, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); + LogRenderedText(&render_text_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); if (label_size.x > 0.0f) - RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); + RenderText(render_text_pos, label); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); return pressed; @@ -1198,10 +1206,11 @@ bool ImGui::RadioButton(const char* label, bool active) window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize); } + ImVec2 render_text_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); if (g.LogEnabled) - LogRenderedText(&total_bb.Min, active ? "(x)" : "( )"); + LogRenderedText(&render_text_pos, active ? "(x)" : "( )"); if (label_size.x > 0.0f) - RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); + RenderText(render_text_pos, label); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); return pressed; @@ -1385,7 +1394,11 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) // Draw window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator)); if (g.LogEnabled) + { LogRenderedText(&bb.Min, "--------------------------------"); + LogRenderedTextNewLine(); // Separator isn't tall enough to trigger a new line automatically in LogRenderText + } + } if (columns) { @@ -5799,11 +5812,10 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l if (g.LogEnabled) { // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here. - const char log_prefix[] = "\n##"; - const char log_suffix[] = "##"; - LogRenderedText(&text_pos, log_prefix, log_prefix + 3); + const char log_prefix[] = "##"; + LogRenderedText(&text_pos, log_prefix, log_prefix + 2); RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); - LogRenderedText(&text_pos, log_suffix, log_suffix + 2); + LogRenderedText(&text_pos, log_prefix, log_prefix + 2); } else { From 929563c3a7905f502436d121b7ff5f4ce1ac0ae6 Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 2 Feb 2021 09:42:23 +0100 Subject: [PATCH 07/18] Log/Capture: Fixes for handling \n in strings. Improve the look of various widgets. Added LogSetNextTextDecoration helper. Fixup/amend dbaf74d75. For now removed LogRenderedTextNewLine() - it is eventually desirable but currently carries too much ambiguities, so reverted until we have a better system and test suite. --- docs/CHANGELOG.txt | 11 ++------ docs/TODO.txt | 4 ++- imgui.cpp | 69 ++++++++++++++++++++++++++-------------------- imgui_internal.h | 7 +++-- imgui_tables.cpp | 12 ++++++++ imgui_widgets.cpp | 55 +++++++++++++++++------------------- 6 files changed, 87 insertions(+), 71 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 58b8f9ec1..602087358 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -30,15 +30,6 @@ HOW TO UPDATE? and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. - Please report any issue! ------------------------------------------------------------------------ - VERSION 1.81 (In Progress) ------------------------------------------------------------------------ - -Other Changes: - -- Log/Capture: Fix various new line/spacing issue by using same render text position when there are both - RenderText and LogRenderedText call in widget code. - Also Buttons are now enclosed in bracket. [@Xipiryon] ----------------------------------------------------------------------- VERSION 1.81 WIP (In Progress) @@ -71,6 +62,8 @@ Other Changes: to have enough space when provided width precisely calculated with CalcTextSize().x. (#3776) Note that the rounding of either positions and widths are technically undesirable (e.g. #3437, #791) but variety of code is currently on it so we are first fixing current behavior before we'll eventually change it. +- Log/Capture: Fix various new line/spacing issue when logging widgets. [@Xipiryon, @ocornut] +- Log/Capture: Improved the ascii look of various widgets, making large dumps more easily human readable. - ImDrawList: Fixed AddCircle()/AddCircleFilled() with (rad > 0.0f && rad < 1.0f && num_segments == 0). (#3738) Would lead to a buffer read overflow. - Backends: Win32: Dynamically loading XInput DLL instead of linking with it, facilite compiling with diff --git a/docs/TODO.txt b/docs/TODO.txt index f9b94567e..93f00c352 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -247,12 +247,14 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - style: gradients fill (#1223) ~ 2 bg colors for each fill? tricky with rounded shapes and using textures for corners. - style editor: color child window height expressed in multiple of line height. + - log: improve logging of ArrowButton, ListBox, TabItem + - log: carry on indent / tree depth when opening a child window + - log: enabling log ends up pushing and growing vertices buffers because we don't distinguish layout vs render clipping - log: have more control over the log scope (e.g. stop logging when leaving current tree node scope) - log: be able to log anything (e.g. right-click on a window/tree-node, shows context menu? log into tty/file/clipboard) - log: let user copy any window content to clipboard easily (CTRL+C on windows? while moving it? context menu?). code is commented because it fails with multiple Begin/End pairs. - log: obsolete LogButtons() all together. - log: LogButtons() options for specifying depth and/or hiding depth slider - - log: enabling log ends up pushing and growing vertices buffersbecause we don't distinguish layout vs render clipping - filters: set a current filter that tree node can automatically query to hide themselves - filters: handle wild-cards (with implicit leading/trailing *), reg-exprs diff --git a/imgui.cpp b/imgui.cpp index f1e05c051..e41ee39d4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -4944,6 +4944,7 @@ void ImGui::EndChild() } } g.WithinEndChild = false; + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return } // Helper to create a child window / scrolling region that looks like a normal widget frame. @@ -7572,7 +7573,7 @@ void ImGui::BeginGroup() window->DC.CursorMaxPos = window->DC.CursorPos; window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); if (g.LogEnabled) - LogRenderedTextNewLine(); + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return } void ImGui::EndGroup() @@ -7593,7 +7594,7 @@ void ImGui::EndGroup() window->DC.CurrLineSize = group_data.BackupCurrLineSize; window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset; if (g.LogEnabled) - LogRenderedTextNewLine(); + g.LogLinePosY = -FLT_MAX; // To enforce a carriage return if (!group_data.EmitItem) { @@ -9859,11 +9860,16 @@ void ImGui::LogText(const char* fmt, ...) // Internal version that takes a position to decide on newline placement and pad items according to their depth. // We split text into individual lines to add current tree level padding +// FIXME: This code is a little complicated perhaps, considering simplifying the whole system. void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; + const char* prefix = g.LogNextPrefix; + const char* suffix = g.LogNextSuffix; + g.LogNextPrefix = g.LogNextSuffix = NULL; + if (!text_end) text_end = FindRenderedTextEnd(text, text_end); @@ -9871,52 +9877,46 @@ void ImGui::LogRenderedText(const ImVec2* ref_pos, const char* text, const char* if (ref_pos) g.LogLinePosY = ref_pos->y; if (log_new_line) + { + LogText(IM_NEWLINE); g.LogLineFirstItem = true; + } - const char* text_remaining = text; - if (g.LogDepthRef > window->DC.TreeDepth) // Re-adjust padding if we have popped out of our starting depth + if (prefix) + LogRenderedText(ref_pos, prefix, prefix + strlen(prefix)); // Calculate end ourself to ensure "##" are included here. + + // Re-adjust padding if we have popped out of our starting depth + if (g.LogDepthRef > window->DC.TreeDepth) g.LogDepthRef = window->DC.TreeDepth; const int tree_depth = (window->DC.TreeDepth - g.LogDepthRef); + + const char* text_remaining = text; for (;;) { - // Split the string. Each new line (after a '\n') is followed by spacing corresponding to the current depth of our log entry. - // We don't add a trailing \n to allow a subsequent item on the same line to be captured. + // Split the string. Each new line (after a '\n') is followed by indentation corresponding to the current depth of our log entry. + // We don't add a trailing \n yet to allow a subsequent item on the same line to be captured. const char* line_start = text_remaining; const char* line_end = ImStreolRange(line_start, text_end); - const bool is_first_line = (line_start == text); const bool is_last_line = (line_end == text_end); - if (!is_last_line || (line_start != line_end)) + if (line_start != line_end || !is_last_line) { - const int char_count = (int)(line_end - line_start); - if (log_new_line || !is_first_line) - LogText(IM_NEWLINE "%*s%.*s", tree_depth * 4, "", char_count, line_start); - else if (g.LogLineFirstItem) - LogText("%*s%.*s", tree_depth * 4, "", char_count, line_start); - else - LogText(" %.*s", char_count, line_start); + const int line_length = (int)(line_end - line_start); + const int indentation = g.LogLineFirstItem ? tree_depth * 4 : 1; + LogText("%*s%.*s", indentation, "", line_length, line_start); g.LogLineFirstItem = false; - if (*line_end == '\n') - LogRenderedTextNewLine(); + { + LogText(IM_NEWLINE); + g.LogLineFirstItem = true; + } } - else if (log_new_line) - { - // An empty "" string at a different Y position should output a carriage return. - LogText(IM_NEWLINE); - break; - } - if (is_last_line) break; text_remaining = line_end + 1; } -} -void ImGui::LogRenderedTextNewLine() -{ - // To enforce Log carriage return - ImGuiContext& g = *GImGui; - g.LogLinePosY = -FLT_MAX; + if (suffix) + LogRenderedText(ref_pos, suffix, suffix + strlen(suffix)); } // Start logging/capturing text output @@ -9929,12 +9929,21 @@ void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth) IM_ASSERT(g.LogBuffer.empty()); g.LogEnabled = true; g.LogType = type; + g.LogNextPrefix = g.LogNextSuffix = NULL; g.LogDepthRef = window->DC.TreeDepth; g.LogDepthToExpand = ((auto_open_depth >= 0) ? auto_open_depth : g.LogDepthToExpandDefault); g.LogLinePosY = FLT_MAX; g.LogLineFirstItem = true; } +// Important: doesn't copy underlying data, use carefully (prefix/suffix must be in scope at the time of the next LogRenderedText) +void ImGui::LogSetNextTextDecoration(const char* prefix, const char* suffix) +{ + ImGuiContext& g = *GImGui; + g.LogNextPrefix = prefix; + g.LogNextSuffix = suffix; +} + void ImGui::LogToTTY(int auto_open_depth) { ImGuiContext& g = *GImGui; diff --git a/imgui_internal.h b/imgui_internal.h index 779c62955..0745df30a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1469,6 +1469,8 @@ struct ImGuiContext ImGuiLogType LogType; // Capture target ImFileHandle LogFile; // If != NULL log to stdout/ file ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. + const char* LogNextPrefix; + const char* LogNextSuffix; float LogLinePosY; bool LogLineFirstItem; int LogDepthRef; @@ -1620,6 +1622,7 @@ struct ImGuiContext LogEnabled = false; LogType = ImGuiLogType_None; + LogNextPrefix = LogNextSuffix = NULL; LogFile = NULL; LogLinePosY = FLT_MAX; LogLineFirstItem = false; @@ -2253,6 +2256,8 @@ namespace ImGui // Logging/Capture IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name. IMGUI_API void LogToBuffer(int auto_open_depth = -1); // Start logging/capturing to internal buffer + IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); + IMGUI_API void LogSetNextTextDecoration(const char* prefix, const char* suffix); // Popups, Modals, Tooltips IMGUI_API bool BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags flags); @@ -2391,8 +2396,6 @@ namespace ImGui IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0); IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text. - IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL); - IMGUI_API void LogRenderedTextNewLine(); // Render helpers (those functions don't access any ImGui state!) IMGUI_API void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f); diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 9681e726a..6799d290f 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -1654,6 +1654,10 @@ void ImGui::TableEndRow(ImGuiTable* table) if (table->CurrentColumn != -1) TableEndCell(table); + // Logging + if (g.LogEnabled) + LogRenderedText(NULL, "|"); + // Position cursor at the bottom of our row so it can be used for e.g. clipping calculation. However it is // likely that the next call to TableBeginCell() will reposition the cursor to take account of vertical padding. window->DC.CursorPos.y = table->RowPosY2; @@ -1890,6 +1894,14 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n) SetWindowClipRectBeforeSetChannel(window, column->ClipRect); table->DrawSplitter.SetCurrentChannel(window->DrawList, column->DrawChannelCurrent); } + + // Logging + ImGuiContext& g = *GImGui; + if (g.LogEnabled && !column->IsSkipItems) + { + LogRenderedText(&window->DC.CursorPos, "|"); + g.LogLinePosY = FLT_MAX; + } } // [Internal] Called by TableNextRow()/TableSetColumnIndex()/TableNextColumn() diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index cea0fb416..d159188c1 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -693,12 +693,9 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags RenderNavHighlight(bb, id); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); - ImRect render_text_pos = ImRect(bb.Min + style.FramePadding, bb.Max - style.FramePadding); if (g.LogEnabled) - LogRenderedText(&render_text_pos.Min, "["); - RenderTextClipped(render_text_pos.Min, render_text_pos.Max ,label, NULL, &label_size, style.ButtonTextAlign, &bb); - if (g.LogEnabled) - LogRenderedText(&render_text_pos.Min, "]"); + LogSetNextTextDecoration("[", "]"); + RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb); // Automatically close popups //if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup)) @@ -1103,12 +1100,11 @@ bool ImGui::Checkbox(const char* label, bool* v) RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f); } - - ImVec2 render_text_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); if (g.LogEnabled) - LogRenderedText(&render_text_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); + LogRenderedText(&label_pos, mixed_value ? "[~]" : *v ? "[x]" : "[ ]"); if (label_size.x > 0.0f) - RenderText(render_text_pos, label); + RenderText(label_pos, label); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); return pressed; @@ -1206,11 +1202,11 @@ bool ImGui::RadioButton(const char* label, bool active) window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize); } - ImVec2 render_text_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); + ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y); if (g.LogEnabled) - LogRenderedText(&render_text_pos, active ? "(x)" : "( )"); + LogRenderedText(&label_pos, active ? "(x)" : "( )"); if (label_size.x > 0.0f) - RenderText(render_text_pos, label); + RenderText(label_pos, label); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags); return pressed; @@ -1394,10 +1390,7 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags) // Draw window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator)); if (g.LogEnabled) - { - LogRenderedText(&bb.Min, "--------------------------------"); - LogRenderedTextNewLine(); // Separator isn't tall enough to trigger a new line automatically in LogRenderText - } + LogRenderedText(&bb.Min, "--------------------------------\n"); } if (columns) @@ -1589,7 +1582,12 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF } RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding); if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview)) - RenderTextClipped(frame_bb.Min + style.FramePadding, ImVec2(value_x2, frame_bb.Max.y), preview_value, NULL, NULL, ImVec2(0.0f, 0.0f)); + { + ImVec2 preview_pos = frame_bb.Min + style.FramePadding; + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); + RenderTextClipped(preview_pos, ImVec2(value_x2, frame_bb.Max.y), preview_value, NULL, NULL, ImVec2(0.0f, 0.0f)); + } if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -2339,6 +2337,8 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); if (label_size.x > 0.0f) @@ -2951,6 +2951,8 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat // Display value using user-provided display format so user can add prefix/suffix/decorations to the value. char value_buf[64]; const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format); + if (g.LogEnabled) + LogSetNextTextDecoration("{", "}"); RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f)); if (label_size.x > 0.0f) @@ -4602,7 +4604,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Log as text if (g.LogEnabled && (!is_password || is_displaying_hint)) + { + LogSetNextTextDecoration("{", "}"); LogRenderedText(&draw_pos, buf_display, buf_display_end); + } if (label_size.x > 0) RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); @@ -5809,18 +5814,10 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l text_pos.x -= text_offset_x; if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton) frame_bb.Max.x -= g.FontSize + style.FramePadding.x; + if (g.LogEnabled) - { - // NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here. - const char log_prefix[] = "##"; - LogRenderedText(&text_pos, log_prefix, log_prefix + 2); - RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); - LogRenderedText(&text_pos, log_prefix, log_prefix + 2); - } - else - { - RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); - } + LogSetNextTextDecoration("###", "###"); + RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size); } else { @@ -5836,7 +5833,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l else if (!is_leaf) RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f); if (g.LogEnabled) - LogRenderedText(&text_pos, ">"); + LogSetNextTextDecoration(">", NULL); RenderText(text_pos, label, label_end, false); } From a3f03933516ee2a9c7e5cdcf1eb0e1fa4373195e Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 2 Feb 2021 13:06:51 +0100 Subject: [PATCH 08/18] Menus: Fixed an issue with child-menu auto-sizing (issue introduced by 6af92b0) (#3779) --- docs/CHANGELOG.txt | 5 +++-- imgui.cpp | 1 + imgui.h | 2 +- imgui_widgets.cpp | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 602087358..b6f18788a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -50,12 +50,13 @@ Other Changes: close button in the window. (#3731) - SliderInt: Fixed click/drag when v_min==v_max from setting the value to zero. (#3774) [@erwincoumans] Would also repro with DragFloat() when using ImGuiSliderFlags_Logarithmic with v_min==v_max. -- imgui_freetype: Facilitated using FreeType integration: [@Xipiryon, @ocornut] +- Menus: Fixed an issue with child-menu auto sizing (issue introduced in 1.80 on 2021/01/25) (#3779) +- Fonts: imgui_freetype: Facilitated using FreeType integration: [@Xipiryon, @ocornut] - Use '#define IMGUI_ENABLE_FREETYPE' in imconfig.h should make it work with no other modifications other than compiling misc/freetype/imgui_freetype.cpp and linking with FreeType. - Use '#define IMGUI_ENABLE_STB_TRUETYPE' if you somehow need the stb_truetype rasterizer to be compiled in along with the FreeType one, otherwise it is enabled by default. -- imgui_freetype: Added support for colored glyphs as supported by Freetype 2.10+ (for .ttf using CPAL/COLR +- Fonts: imgui_freetype: Added support for colored glyphs as supported by Freetype 2.10+ (for .ttf using CPAL/COLR tables only). Enable the ImGuiFreeTypeBuilderFlags_LoadColor on a given font. Atlas always output directly as RGBA8 in this situation. Likely to make sense with IMGUI_USE_WCHAR32. (#3369) [@pshurgal] - Fonts: Fixed CalcTextSize() width rounding so it behaves more like a ceil. This is in order for text wrapping diff --git a/imgui.cpp b/imgui.cpp index e41ee39d4..58e6966f3 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -6576,6 +6576,7 @@ void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond) ImVec2 offset = window->Pos - old_pos; window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected. + window->DC.IdealMaxPos += offset; window->DC.CursorStartPos += offset; } diff --git a/imgui.h b/imgui.h index a241cfb61..3fc57c452 100644 --- a/imgui.h +++ b/imgui.h @@ -59,7 +59,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.81 WIP" -#define IMGUI_VERSION_NUM 18002 +#define IMGUI_VERSION_NUM 18003 #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_widgets.cpp b/imgui_widgets.cpp index d159188c1..2daf213aa 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6758,7 +6758,7 @@ bool ImGui::BeginMenu(const char* label, bool enabled) if (menu_is_open) { - SetNextWindowPos(popup_pos, ImGuiCond_Always); + SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: this is super misleading! The value will serve as reference for FindBestWindowPosForPopup(), not actual pos. menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display) } else From d1a9efdd8f90b09df1ae380403992e8a997f7ede Mon Sep 17 00:00:00 2001 From: ocornut Date: Tue, 2 Feb 2021 16:02:46 +0100 Subject: [PATCH 09/18] InputText: Fixed slightly off ScrollX tracking, noticeable with large values of FramePadding.x. Multiline: Fixed padding/cliprect not matching single-line version. (#3781) Fixed FramePadding.y worth of vertical offset when aiming with mouse. --- docs/CHANGELOG.txt | 3 +++ imgui_widgets.cpp | 15 ++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index b6f18788a..5bf06ed1d 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -51,6 +51,9 @@ Other Changes: - SliderInt: Fixed click/drag when v_min==v_max from setting the value to zero. (#3774) [@erwincoumans] Would also repro with DragFloat() when using ImGuiSliderFlags_Logarithmic with v_min==v_max. - Menus: Fixed an issue with child-menu auto sizing (issue introduced in 1.80 on 2021/01/25) (#3779) +- InputText: Fixed slightly off ScrollX tracking, noticeable with large values of FramePadding.x. (#3781) +- InputText: Multiline: Fixed padding/cliprect not precisely matching single-line version. (#3781) +- InputText: Multiline: Fixed FramePadding.y worth of vertical offset when aiming with mouse. - Fonts: imgui_freetype: Facilitated using FreeType integration: [@Xipiryon, @ocornut] - Use '#define IMGUI_ENABLE_FREETYPE' in imconfig.h should make it work with no other modifications other than compiling misc/freetype/imgui_freetype.cpp and linking with FreeType. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2daf213aa..159e27b7c 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -3868,9 +3868,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]); PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding); PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize); - PushStyleVar(ImGuiStyleVar_WindowPadding, style.FramePadding); - bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_AlwaysUseWindowPadding); - PopStyleVar(3); + bool child_visible = BeginChildEx(label, id, frame_bb.GetSize(), true, ImGuiWindowFlags_NoMove); + PopStyleVar(2); PopStyleColor(); if (!child_visible) { @@ -3880,6 +3879,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ } draw_window = g.CurrentWindow; // Child window draw_window->DC.NavLayerActiveMaskNext |= (1 << draw_window->DC.NavLayerCurrent); // This is to ensure that EndChild() will display a navigation highlight so we can "enter" into it. + draw_window->DC.CursorPos += style.FramePadding; inner_size.x -= draw_window->ScrollbarSizes.x; } else @@ -4040,7 +4040,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ // Edit in progress const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX; - const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y - style.FramePadding.y) : (g.FontSize * 0.5f)); + const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f)); const bool is_osx = io.ConfigMacOSXBehaviors; if (select_all || (hovered && !is_osx && io.MouseDoubleClicked[0])) @@ -4489,10 +4489,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll)) { const float scroll_increment_x = inner_size.x * 0.25f; + const float visible_width = inner_size.x - style.FramePadding.x; if (cursor_offset.x < state->ScrollX) state->ScrollX = IM_FLOOR(ImMax(0.0f, cursor_offset.x - scroll_increment_x)); - else if (cursor_offset.x - inner_size.x >= state->ScrollX) - state->ScrollX = IM_FLOOR(cursor_offset.x - inner_size.x + scroll_increment_x); + else if (cursor_offset.x - visible_width >= state->ScrollX) + state->ScrollX = IM_FLOOR(cursor_offset.x - visible_width + scroll_increment_x); } else { @@ -4597,7 +4598,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_ if (is_multiline) { - Dummy(text_size); + Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y)); EndChild(); EndGroup(); } From 90a518c50186548a2f02f658bfeb59553d2fb797 Mon Sep 17 00:00:00 2001 From: freddii Date: Wed, 3 Feb 2021 02:50:57 +0100 Subject: [PATCH 10/18] Fixed typos (#3782) --- docs/CHANGELOG.txt | 10 +++++----- imgui.h | 2 +- imgui_internal.h | 4 ++-- imgui_tables.cpp | 6 +++--- imgui_widgets.cpp | 4 ++-- imstb_truetype.h | 2 +- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 5bf06ed1d..0ceae5cd8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -247,7 +247,7 @@ Other Changes: - InputText: Fixed callback's helper DeleteChars() function when cursor is inside the deleted block. (#3454) - InputText: Made pressing Down arrow on the last line when it doesn't have a carriage return not move to the end of the line (so it is consistent with Up arrow, and behave same as Notepad and Visual Studio. - Note that some other text editors instead would move the crusor to the end of the line). [@Xipiryon] + Note that some other text editors instead would move the cursor to the end of the line). [@Xipiryon] - DragFloat, DragScalar: Fixed ImGuiSliderFlags_ClampOnInput not being honored in the special case where v_min == v_max. (#3361) - SliderInt, SliderScalar: Fixed reaching of maximum value with inverted integer min/max ranges, both @@ -275,7 +275,7 @@ Other Changes: tabs reordered in the tab list popup. [@Xipiryon] - Columns: Fix inverted ClipRect being passed to renderer when using certain primitives inside of a fully clipped column. (#3475) [@szreder] -- Popups, Tooltips: Fix edge cases issues with positionning popups and tooltips when they are larger than +- Popups, Tooltips: Fix edge cases issues with positioning popups and tooltips when they are larger than viewport on either or both axises. [@Rokups] - Fonts: AddFontDefault() adjust its vertical offset based on floor(size/13) instead of always +1. Was previously done by altering DisplayOffset.y but wouldn't work for DPI scaled font. @@ -439,7 +439,7 @@ Other Changes: - Popups: Added ImGuiPopupFlags_AnyPopupId and ImGuiPopupFlags_AnyPopupLevel flags for IsPopupOpen(), allowing to check if any popup is open at the current level, if a given popup is open at any popup level, if any popup is open at all. -- Popups: Fix an edge case where programatically closing a popup while clicking on its empty space +- Popups: Fix an edge case where programmatically closing a popup while clicking on its empty space would attempt to focus it and close other popups. (#2880) - Popups: Fix BeginPopupContextVoid() when clicking over the area made unavailable by a modal. (#1636) - Popups: Clarified some of the comments and function prototypes. @@ -1576,7 +1576,7 @@ Other Changes: - ImFontAtlas: Added GetGlyphRangesChineseSimplifiedCommon() helper that returns a list of ~2500 most common Simplified Chinese characters. (#1859) [@JX-Master, @ocornut] - Examples: OSX: Added imgui_impl_osx.mm backend to be used along with e.g. imgui_impl_opengl2.cpp. (#281, #1870) [@pagghiu, @itamago, @ocornut] -- Examples: GLFW: Made it possible to Shutdown/Init the backend again (by reseting the time storage properly). (#1827) [@ice1000] +- Examples: GLFW: Made it possible to Shutdown/Init the backend again (by resetting the time storage properly). (#1827) [@ice1000] - Examples: Win32: Fixed handling of mouse wheel messages to support sub-unit scrolling messages (typically sent by track-pads). (#1874) [@zx64] - Examples: SDL+Vulkan: Added SDL+Vulkan example. - Examples: Allegro5: Added support for ImGuiConfigFlags_NoMouseCursorChange flag. Added clipboard support. @@ -2351,7 +2351,7 @@ Other Changes: - Combo(): Right-most button stays highlighted when pop-up is open. - Combo(): Display pop-up above if there's isn't enough space below / or select largest side. (#505) - DragFloat(), SliderFloat(), InputFloat(): fixed cases of erroneously returning true repeatedly after a text input modification (e.g. "0.0" --> "0.000" would keep returning true). (#564) -- DragFloat(): Always apply value when mouse is held/widget active, so that an always-reseting variable (e.g. non saved local) can be passed. +- DragFloat(): Always apply value when mouse is held/widget active, so that an always-resetting variable (e.g. non saved local) can be passed. - InputText(): OS X friendly behaviors: Word movement uses ALT key; Shortcuts uses CMD key; Double-clicking text select a single word; Jumping to next word sets cursor to end of current word instead of beginning of current word. (@zhiayang), (#473) - InputText(): Added BufTextLen in ImGuiTextEditCallbackData. Requesting user to maintain it if buffer is modified. Zero-ing structure properly before use. (#541) - CheckboxFlags(): Added support for testing/setting multiple flags at the same time. (@DMartinek) (#555) diff --git a/imgui.h b/imgui.h index 3fc57c452..4ab0c9072 100644 --- a/imgui.h +++ b/imgui.h @@ -1085,7 +1085,7 @@ enum ImGuiTableFlags_ ImGuiTableFlags_SizingFixedFit = 1 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching contents width. ImGuiTableFlags_SizingFixedSame = 2 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching the maximum contents width of all columns. Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible. ImGuiTableFlags_SizingStretchProp = 3 << 13, // Columns default to _WidthStretch with default weights proportional to each columns contents widths. - ImGuiTableFlags_SizingStretchSame = 4 << 13, // Columns default to _WidthStretch with default weights all equal, unless overriden by TableSetupColumn(). + ImGuiTableFlags_SizingStretchSame = 4 << 13, // Columns default to _WidthStretch with default weights all equal, unless overridden by TableSetupColumn(). // Sizing Extra Options ImGuiTableFlags_NoHostExtendX = 1 << 16, // Make outer width auto-fit to columns, overriding outer_size.x value. Only available when ScrollX/ScrollY are disabled and Stretch columns are not used. ImGuiTableFlags_NoHostExtendY = 1 << 17, // Make outer height stop exactly at outer_size.y (prevent auto-extending table past the limit). Only available when ScrollX/ScrollY are disabled. Data below the limit will be clipped and not visible. diff --git a/imgui_internal.h b/imgui_internal.h index 0745df30a..16e5b16a1 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -2086,7 +2086,7 @@ struct ImGuiTable ImGuiTableColumnIdx FreezeColumnsCount; // Actual frozen columns count (== FreezeColumnsRequest, or == 0 when no scrolling offset) ImGuiTableColumnIdx RowCellDataCurrent; // Index of current RowCellData[] entry in current row ImGuiTableDrawChannelIdx DummyDrawChannel; // Redirect non-visible columns here. - ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; // For Selectable() and other widgets drawing accross columns after the freezing line. Index within DrawSplitter.Channels[] + ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; // For Selectable() and other widgets drawing across columns after the freezing line. Index within DrawSplitter.Channels[] ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen; bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row. bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow(). @@ -2100,7 +2100,7 @@ struct ImGuiTable bool IsResetAllRequest; bool IsResetDisplayOrderRequest; bool IsUnfrozenRows; // Set when we got past the frozen row. - bool IsDefaultSizingPolicy; // Set if user didn't explicitely set a sizing policy in BeginTable() + bool IsDefaultSizingPolicy; // Set if user didn't explicitly set a sizing policy in BeginTable() bool MemoryCompacted; bool HostSkipItems; // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 6799d290f..088726e7d 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -126,12 +126,12 @@ Index of this file: // - with Table policy ImGuiTableFlags_SizingFixedSame --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is max of all contents width // - with Table policy ImGuiTableFlags_SizingStretchSame --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is 1.0f // - with Table policy ImGuiTableFlags_SizingStretchWeight --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is proportional to contents -// Default Width and default Weight can be overriden when calling TableSetupColumn(). +// Default Width and default Weight can be overridden when calling TableSetupColumn(). //----------------------------------------------------------------------------- // About mixing Fixed/Auto and Stretch columns together: // - the typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. // - using mixed policies with ScrollX does not make much sense, as using Stretch columns with ScrollX does not make much sense in the first place! -// that is, unless 'inner_width' is passed to BeginTable() to explicitely provide a total width to layout columns in. +// that is, unless 'inner_width' is passed to BeginTable() to explicitly provide a total width to layout columns in. // - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the maximum contents width. // - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weight/widths. //----------------------------------------------------------------------------- @@ -1367,7 +1367,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo // Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa. // Give a grace to users of ImGuiTableFlags_ScrollX. if (table->IsDefaultSizingPolicy && (flags & ImGuiTableColumnFlags_WidthMask_) == 0 && (flags & ImGuiTableFlags_ScrollX) == 0) - IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitely in either Table or Column."); + IM_ASSERT(init_width_or_weight <= 0.0f && "Can only specify width/weight if sizing policy is set explicitly in either Table or Column."); // When passing a width automatically enforce WidthFixed policy // (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 159e27b7c..0bd932b48 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -5985,7 +5985,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl ItemSize(size, 0.0f); // Fill horizontal space - // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitely right-aligned sizes not visibly match other widgets. + // We don't support (size < 0.0f) in Selectable() because the ItemSpacing extension would make explicitly right-aligned sizes not visibly match other widgets. const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0; const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x; const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x; @@ -6523,7 +6523,7 @@ bool ImGui::BeginMenuBar() clip_rect.ClipWith(window->OuterRectClipped); PushClipRect(clip_rect.Min, clip_rect.Max, false); - // We overwrite CursorMaxPos because BeginGroup sets it to CursorPos (essentially the .EmitItem hack in EndMenuBar() would need something analoguous here, maybe a BeginGroupEx() with flags). + // We overwrite CursorMaxPos because BeginGroup sets it to CursorPos (essentially the .EmitItem hack in EndMenuBar() would need something analogous here, maybe a BeginGroupEx() with flags). window->DC.CursorPos = window->DC.CursorMaxPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y); window->DC.LayoutType = ImGuiLayoutType_Horizontal; window->DC.NavLayerCurrent = ImGuiNavLayer_Menu; diff --git a/imstb_truetype.h b/imstb_truetype.h index b4bdbd869..fc815d745 100644 --- a/imstb_truetype.h +++ b/imstb_truetype.h @@ -4302,7 +4302,7 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex int winding = 0; orig[0] = x; - //orig[1] = y; // [DEAR IMGUI] commmented double assignment + //orig[1] = y; // [DEAR IMGUI] commented double assignment // make sure y never passes through a vertex of the shape y_frac = (float) STBTT_fmod(y, 1.0f); From e5cbf60defac41c6c63316d4e01b4fb0928f09b1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 3 Feb 2021 14:16:08 +0100 Subject: [PATCH 11/18] ListBox: tweaked default height calculation. simplifying code internally (rework passing of full rect). Should have no visible side-effects + misc comments. --- docs/CHANGELOG.txt | 10 ++++++---- imgui.cpp | 6 +++--- imgui.h | 1 + imgui_demo.cpp | 6 +++--- imgui_widgets.cpp | 47 ++++++++++++++++++++++------------------------ 5 files changed, 35 insertions(+), 35 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 0ceae5cd8..786a76fa0 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -37,11 +37,12 @@ HOW TO UPDATE? Breaking Changes: -- imgui_freetype: Removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. +- imgui_freetype: + - Removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. - The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. -- imgui_freetype: Renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. -- imgui_freetyoe: Renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. + - The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. + - Renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. + - Renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. Other Changes: @@ -54,6 +55,7 @@ Other Changes: - InputText: Fixed slightly off ScrollX tracking, noticeable with large values of FramePadding.x. (#3781) - InputText: Multiline: Fixed padding/cliprect not precisely matching single-line version. (#3781) - InputText: Multiline: Fixed FramePadding.y worth of vertical offset when aiming with mouse. +- ListBox: Tweaked default height calculation. - Fonts: imgui_freetype: Facilitated using FreeType integration: [@Xipiryon, @ocornut] - Use '#define IMGUI_ENABLE_FREETYPE' in imconfig.h should make it work with no other modifications other than compiling misc/freetype/imgui_freetype.cpp and linking with FreeType. diff --git a/imgui.cpp b/imgui.cpp index 58e6966f3..846bc5d39 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -373,9 +373,9 @@ CODE When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. - - 2021/01/26 (1.81) - imgui_freetype: removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. - - imgui_freetype: renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. - - imgui_freetype: renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. + - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. + - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. + - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. - 2020/10/12 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018): - ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit(). - ImGuiCol_ModalWindowDarkening -> use ImGuiCol_ModalWindowDimBg diff --git a/imgui.h b/imgui.h index 4ab0c9072..adcc54446 100644 --- a/imgui.h +++ b/imgui.h @@ -587,6 +587,7 @@ namespace ImGui IMGUI_API void ListBoxFooter(); // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true! // Widgets: Data Plotting + // - Consider using ImPlot (https://github.com/epezent/implot) IMGUI_API void PlotLines(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); IMGUI_API void PlotLines(const char* label, float(*values_getter)(void* data, int idx), void* data, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0)); IMGUI_API void PlotHistogram(const char* label, const float* values, int values_count, int values_offset = 0, const char* overlay_text = NULL, float scale_min = FLT_MAX, float scale_max = FLT_MAX, ImVec2 graph_size = ImVec2(0, 0), int stride = sizeof(float)); diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 8d52ea356..ee5a9cb1f 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -695,7 +695,7 @@ static void ShowDemoWindowWidgets() ImGui::ListBox("listbox\n(single select)", &item_current, items, IM_ARRAYSIZE(items), 4); //static int listbox_item_current2 = 2; - //ImGui::SetNextItemWidth(-1); + //ImGui::SetNextItemWidth(-FLT_MIN); //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); } @@ -3146,7 +3146,7 @@ static void ShowDemoWindowPopups() { if (ImGui::Selectable("Set to zero")) value = 0.0f; if (ImGui::Selectable("Set to PI")) value = 3.1415f; - ImGui::SetNextItemWidth(-1); + ImGui::SetNextItemWidth(-FLT_MIN); ImGui::DragFloat("##Value", &value, 0.1f, 0.0f, 0.0f); ImGui::EndPopup(); } @@ -7478,7 +7478,7 @@ void ShowExampleAppDocuments(bool* p_open) if (ImGui::BeginPopupModal("Save?")) { ImGui::Text("Save change to the following items?"); - ImGui::SetNextItemWidth(-1.0f); + ImGui::SetNextItemWidth(-FLT_MIN); if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6)) { for (int n = 0; n < close_queue.Size; n++) diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 0bd932b48..df1c16e31 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6129,12 +6129,12 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags // - ListBoxFooter() //------------------------------------------------------------------------- // FIXME: This is an old API. We should redesign some of it, rename ListBoxHeader->BeginListBox, ListBoxFooter->EndListBox -// and promote using them over existing ListBox() functions, similarly to change with combo boxes. +// and promote using them over existing ListBox() functions, similarly to how we now use combo boxes. //------------------------------------------------------------------------- // FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature. -// Helper to calculate the size of a listbox and display a label on the right. -// Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty" +// Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty" +// Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.25 * item_height). bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) { ImGuiContext& g = *GImGui; @@ -6146,12 +6146,12 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) const ImGuiID id = GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - // Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. - ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y); + // Size default to hold ~7.25 items. + // Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar. + ImVec2 size = ImFloor(CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.25f + style.FramePadding.y * 2.0f)); ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y)); ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size); ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f)); - window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy. g.NextItemData.ClearFlags(); if (!IsRectVisible(bb.Min, bb.Max)) @@ -6161,50 +6161,46 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) return false; } + // FIXME-OPT: We could omit the BeginGroup() if label_size.x but would need to omit the EndGroup() as well. BeginGroup(); - if (label_size.x > 0) - RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label); + if (label_size.x > 0.0f) + { + ImVec2 label_pos = ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y); + RenderText(label_pos, label); + window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size); + } BeginChildFrame(id, frame_bb.GetSize()); return true; } -// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. +// FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature. bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) { // Size default to hold ~7.25 items. // We add +25% worth of item height to allow the user to see at a glance if there are more items up/down, without looking at the scrollbar. // We don't add this extra bit if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size. // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution. + ImGuiContext& g = *GImGui; if (height_in_items < 0) height_in_items = ImMin(items_count, 7); - const ImGuiStyle& style = GetStyle(); float height_in_items_f = (height_in_items < items_count) ? (height_in_items + 0.25f) : (height_in_items + 0.00f); - // We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild(). ImVec2 size; size.x = 0.0f; - size.y = ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + style.FramePadding.y * 2.0f); + size.y = GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f; return ListBoxHeader(label, size); } // FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. void ImGui::ListBoxFooter() { - ImGuiWindow * window = GetCurrentWindow(); + ImGuiContext& g = *GImGui; + ImGuiWindow* window = g.CurrentWindow; IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched ListBoxHeader/ListBoxFooter calls. Did you test the return value of ListBoxHeader()?"); - ImGuiWindow* parent_window = window->ParentWindow; - const ImRect bb = parent_window->DC.LastItemRect; - const ImGuiStyle& style = GetStyle(); EndChildFrame(); - - // Redeclare item size so that it includes the label (we have stored the full size in LastItemRect) - // We call SameLine() to restore DC.CurrentLine* data - SameLine(); - parent_window->DC.CursorPos = bb.Min; - ItemSize(bb, style.FramePadding.y); - EndGroup(); + EndGroup(); // This is only required to be able to do IsItemXXX query on the whole ListBox including label } bool ImGui::ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_items) @@ -6218,7 +6214,8 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v if (!ListBoxHeader(label, items_count, height_in_items)) return false; - // Assume all items have even height (= 1 line of text). If you need items of different or variable sizes you can create a custom version of ListBox() in your code without using the clipper. + // Assume all items have even height (= 1 line of text). If you need items of different height, + // you can create a custom version of ListBox() in your code without using the clipper. ImGuiContext& g = *GImGui; bool value_changed = false; ImGuiListClipper clipper; @@ -6226,12 +6223,12 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - const bool item_selected = (i == *current_item); const char* item_text; if (!items_getter(data, i, &item_text)) item_text = "*Unknown item*"; PushID(i); + const bool item_selected = (i == *current_item); if (Selectable(item_text, item_selected)) { *current_item = i; From 6f6d4e0b702a69aef1526d690513b9d4b68d97eb Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 3 Feb 2021 14:55:17 +0100 Subject: [PATCH 12/18] ListBoxHeader: In version taking height in number of items, made vertical padding consistent regardless of if (items_count <= height_in_items) or not. Demo: Tweaks. --- docs/CHANGELOG.txt | 2 ++ imgui_demo.cpp | 15 ++++++++------- imgui_widgets.cpp | 10 ++-------- 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 786a76fa0..fe1515910 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -56,6 +56,8 @@ Other Changes: - InputText: Multiline: Fixed padding/cliprect not precisely matching single-line version. (#3781) - InputText: Multiline: Fixed FramePadding.y worth of vertical offset when aiming with mouse. - ListBox: Tweaked default height calculation. +- ListBoxHeader: In version taking height in number of items, made vertical padding consistent regardless + of if (items_count <= height_in_items) or not. - Fonts: imgui_freetype: Facilitated using FreeType integration: [@Xipiryon, @ocornut] - Use '#define IMGUI_ENABLE_FREETYPE' in imconfig.h should make it work with no other modifications other than compiling misc/freetype/imgui_freetype.cpp and linking with FreeType. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ee5a9cb1f..ce1d9cb18 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7475,19 +7475,20 @@ void ShowExampleAppDocuments(bool* p_open) { if (!ImGui::IsPopupOpen("Save?")) ImGui::OpenPopup("Save?"); - if (ImGui::BeginPopupModal("Save?")) + if (ImGui::BeginPopupModal("Save?", NULL, ImGuiWindowFlags_AlwaysAutoResize)) { ImGui::Text("Save change to the following items?"); - ImGui::SetNextItemWidth(-FLT_MIN); - if (ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6)) + float item_height = ImGui::GetTextLineHeightWithSpacing(); + if (ImGui::BeginChildFrame(ImGui::GetID("frame"), ImVec2(-FLT_MIN, 6.25f * item_height))) { for (int n = 0; n < close_queue.Size; n++) if (close_queue[n]->Dirty) ImGui::Text("%s", close_queue[n]->Name); - ImGui::ListBoxFooter(); + ImGui::EndChildFrame(); } - if (ImGui::Button("Yes", ImVec2(80, 0))) + ImVec2 button_size(ImGui::GetFontSize() * 7.0f, 0.0f); + if (ImGui::Button("Yes", button_size)) { for (int n = 0; n < close_queue.Size; n++) { @@ -7499,7 +7500,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button("No", ImVec2(80, 0))) + if (ImGui::Button("No", button_size)) { for (int n = 0; n < close_queue.Size; n++) close_queue[n]->DoForceClose(); @@ -7507,7 +7508,7 @@ void ShowExampleAppDocuments(bool* p_open) ImGui::CloseCurrentPopup(); } ImGui::SameLine(); - if (ImGui::Button("Cancel", ImVec2(80, 0))) + if (ImGui::Button("Cancel", button_size)) { close_queue.clear(); ImGui::CloseCurrentPopup(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index df1c16e31..06257e50f 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6177,15 +6177,9 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) // FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature. bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) { - // Size default to hold ~7.25 items. - // We add +25% worth of item height to allow the user to see at a glance if there are more items up/down, without looking at the scrollbar. - // We don't add this extra bit if items_count <= height_in_items. It is slightly dodgy, because it means a dynamic list of items will make the widget resize occasionally when it crosses that size. - // I am expecting that someone will come and complain about this behavior in a remote future, then we can advise on a better solution. + // If height_in_items == -1, default height is maximum 7. ImGuiContext& g = *GImGui; - if (height_in_items < 0) - height_in_items = ImMin(items_count, 7); - float height_in_items_f = (height_in_items < items_count) ? (height_in_items + 0.25f) : (height_in_items + 0.00f); - + float height_in_items_f = (height_in_items < 0 ? ImMin(items_count, 7) : height_in_items) + 0.25f; ImVec2 size; size.x = 0.0f; size.y = GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f; From 03d74a293db1f3fdb16b8a70f424a561f32eaf51 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 3 Feb 2021 16:30:23 +0100 Subject: [PATCH 13/18] ListBox: renamed ListBoxHeader>BeginListBox, ListBoxFooter>EndListBox. Added demo bits. --- docs/CHANGELOG.txt | 10 +++++--- docs/TODO.txt | 3 +-- imgui.cpp | 3 +++ imgui.h | 17 ++++++++---- imgui_demo.cpp | 64 +++++++++++++++++++++++++++++++++++++--------- imgui_widgets.cpp | 36 +++++++++++++++----------- 6 files changed, 96 insertions(+), 37 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index fe1515910..a1c61462b 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -37,9 +37,15 @@ HOW TO UPDATE? Breaking Changes: +- ListBox helpers: + - Renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). + - Renamed ListBoxFooter() to EndListBox(). + - Removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. + In the redirection function, made vertical padding consistent regardless of (items_count <= height_in_items) or not. + - Kept inline redirection function for all threes (will obsolete). - imgui_freetype: - Removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. - Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. + Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. - The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. - Renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. - Renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. @@ -56,8 +62,6 @@ Other Changes: - InputText: Multiline: Fixed padding/cliprect not precisely matching single-line version. (#3781) - InputText: Multiline: Fixed FramePadding.y worth of vertical offset when aiming with mouse. - ListBox: Tweaked default height calculation. -- ListBoxHeader: In version taking height in number of items, made vertical padding consistent regardless - of if (items_count <= height_in_items) or not. - Fonts: imgui_freetype: Facilitated using FreeType integration: [@Xipiryon, @ocornut] - Use '#define IMGUI_ENABLE_FREETYPE' in imconfig.h should make it work with no other modifications other than compiling misc/freetype/imgui_freetype.cpp and linking with FreeType. diff --git a/docs/TODO.txt b/docs/TODO.txt index 93f00c352..f964e3a1c 100644 --- a/docs/TODO.txt +++ b/docs/TODO.txt @@ -185,12 +185,11 @@ It's mostly a bunch of personal notes, probably incomplete. Feel free to query i - combo: flag for BeginCombo to not return true when unchanged (#1182) - combo: a way/helper to customize the combo preview (#1658) - combo/listbox: keyboard control. need InputText-like non-active focus + key handling. considering keyboard for custom listbox (pr #203) - - listbox: refactor and clean the begin/end api - listbox: multiple selection. - listbox: unselect option (#1208) - listbox: make it easier/more natural to implement range-select (need some sort of info/ref about the last clicked/focused item that user can translate to an index?) (wip stash) - listbox: user may want to initial scroll to focus on the one selected value? - - listbox: expose hovered item for a basic ListBox + - listbox: expose hovered item for a simplified ListBox api - listbox: keyboard navigation. - listbox: disable capturing mouse wheel if the listbox has no scrolling. (#1681) - listbox: scrolling should track modified selection. diff --git a/imgui.cpp b/imgui.cpp index 846bc5d39..2aeb49bec 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -373,6 +373,9 @@ CODE When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files. You can read releases logs https://github.com/ocornut/imgui/releases for more details. + - 2021/02/03 (1.81) - renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). Kept inline redirection function (will obsolete). + - removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. Kept inline redirection function (will obsolete). + - renamed ListBoxFooter() to EndListBox(). Kept inline redirection function (will obsolete). - 2021/01/26 (1.81) - removed ImGuiFreeType::BuildFontAtlas(). Kept inline redirection function. Prefer using '#define IMGUI_ENABLE_FREETYPE', but there's a runtime selection path available too. The shared extra flags parameters (very rarely used) are now stored in ImFontAtlas::FontBuilderFlags. - renamed ImFontConfig::RasterizerFlags (used by FreeType) to ImFontConfig::FontBuilderFlags. - renamed ImGuiFreeType::XXX flags to ImGuiFreeTypeBuilderFlags_XXX for consistency with other API. diff --git a/imgui.h b/imgui.h index adcc54446..477a3c6cb 100644 --- a/imgui.h +++ b/imgui.h @@ -472,7 +472,7 @@ namespace ImGui // Widgets: Combo Box // - The BeginCombo()/EndCombo() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() items. - // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. + // - The old Combo() api are helpers over BeginCombo()/EndCombo() which are kept available for convenience purpose. This is analogous to how ListBox are created. IMGUI_API bool BeginCombo(const char* label, const char* preview_value, ImGuiComboFlags flags = 0); IMGUI_API void EndCombo(); // only call EndCombo() if BeginCombo() returns true! IMGUI_API bool Combo(const char* label, int* current_item, const char* const items[], int items_count, int popup_max_height_in_items = -1); @@ -579,12 +579,15 @@ namespace ImGui IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper. // Widgets: List Boxes - // - FIXME: To be consistent with all the newer API, ListBoxHeader/ListBoxFooter should in reality be called BeginListBox/EndListBox. Will rename them. + // - This is essentially a thin wrapper to using BeginChild/EndChild with some stylistic changes. + // - The BeginListBox()/EndListBox() api allows you to manage your contents and selection state however you want it, by creating e.g. Selectable() or any items. + // - The simplified/old ListBox() api are helpers over BeginListBox()/EndListBox() which are kept available for convenience purpose. This is analoguous to how Combos are created. + // - Choose frame width: size.x > 0.0f: custom / size.x < 0.0f or -FLT_MIN: right-align / size.x = 0.0f (default): use current ItemWidth + // - Choose frame height: size.y > 0.0f: custom / size.y < 0.0f or -FLT_MIN: bottom-align / size.y = 0.0f (default): arbitrary default height which can fit ~7 items + IMGUI_API bool BeginListBox(const char* label, const ImVec2& size = ImVec2(0, 0)); // open a framed scrolling region + IMGUI_API void EndListBox(); // only call EndListBox() if BeginListBox() returned true! IMGUI_API bool ListBox(const char* label, int* current_item, const char* const items[], int items_count, int height_in_items = -1); IMGUI_API bool ListBox(const char* label, int* current_item, bool (*items_getter)(void* data, int idx, const char** out_text), void* data, int items_count, int height_in_items = -1); - IMGUI_API bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)); // use if you want to reimplement ListBox() will custom data or interactions. if the function return true, you can output elements then call ListBoxFooter() afterwards. - IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // " - IMGUI_API void ListBoxFooter(); // terminate the scrolling region. only call ListBoxFooter() if ListBoxHeader() returned true! // Widgets: Data Plotting // - Consider using ImPlot (https://github.com/epezent/implot) @@ -1961,6 +1964,10 @@ struct ImGuiTableSortSpecs #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS namespace ImGui { + // OBSOLETED in 1.81 (from February 2021) + IMGUI_API bool ListBoxHeader(const char* label, int items_count, int height_in_items = -1); // Helper to calculate size from items_count and height_in_items + static inline bool ListBoxHeader(const char* label, const ImVec2& size = ImVec2(0, 0)) { return BeginListBox(label, size); } + static inline void ListBoxFooter() { EndListBox(); } // OBSOLETED in 1.79 (from August 2020) static inline void OpenPopupContextItem(const char* str_id = NULL, ImGuiMouseButton mb = 1) { OpenPopupOnItemClick(str_id, mb); } // Bool return value removed. Use IsWindowAppearing() in BeginPopup() instead. Renamed in 1.77, renamed back in 1.79. Sorry! // OBSOLETED in 1.78 (from June 2020) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ce1d9cb18..55a85cda4 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -584,13 +584,12 @@ static void ShowDemoWindowWidgets() { // Using the _simplified_ one-liner Combo() api here - // See "Combo" section for examples of how to use the more complete BeginCombo()/EndCombo() api. + // See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api. const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" }; static int item_current = 0; ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items)); ImGui::SameLine(); HelpMarker( - "Refer to the \"Combo\" section below for an explanation of the full BeginCombo/EndCombo API, " - "and demonstration of various flags.\n"); + "Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API."); } { @@ -689,14 +688,13 @@ static void ShowDemoWindowWidgets() } { - // List box + // Using the _simplified_ one-liner ListBox() api here + // See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api. const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pineapple", "Strawberry", "Watermelon" }; static int item_current = 1; - ImGui::ListBox("listbox\n(single select)", &item_current, items, IM_ARRAYSIZE(items), 4); - - //static int listbox_item_current2 = 2; - //ImGui::SetNextItemWidth(-FLT_MIN); - //ImGui::ListBox("##listbox2", &listbox_item_current2, listbox_items, IM_ARRAYSIZE(listbox_items), 4); + ImGui::ListBox("listbox", &item_current, items, IM_ARRAYSIZE(items), 4); + ImGui::SameLine(); HelpMarker( + "Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API."); } ImGui::TreePop(); @@ -1009,7 +1007,7 @@ static void ShowDemoWindowWidgets() // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively // 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 our selection data is an index. + 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)) { @@ -1042,6 +1040,48 @@ static void ShowDemoWindowWidgets() ImGui::TreePop(); } + if (ImGui::TreeNode("List boxes")) + { + // Using the generic BeginListBox() API, you have full control over how to display the combo contents. + // (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively + // 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. + if (ImGui::BeginListBox("listbox 1")) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_current_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_current_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + + // Custom size: use all width, 5 items tall + ImGui::Text("Full-width:"); + if (ImGui::BeginListBox("##listbox 2", ImVec2(-FLT_MIN, 5 * ImGui::GetTextLineHeightWithSpacing()))) + { + for (int n = 0; n < IM_ARRAYSIZE(items); n++) + { + const bool is_selected = (item_current_idx == n); + if (ImGui::Selectable(items[n], is_selected)) + item_current_idx = n; + + // Set the initial focus when opening the combo (scrolling + keyboard navigation focus) + if (is_selected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndListBox(); + } + + ImGui::TreePop(); + } + if (ImGui::TreeNode("Selectables")) { // Selectable() has 2 overloads: @@ -2557,11 +2597,11 @@ static void ShowDemoWindowLayout() ImGui::Button("LEVERAGE\nBUZZWORD", size); ImGui::SameLine(); - if (ImGui::ListBoxHeader("List", size)) + if (ImGui::BeginListBox("List", size)) { ImGui::Selectable("Selected", true); ImGui::Selectable("Not Selected", false); - ImGui::ListBoxFooter(); + ImGui::EndListBox(); } ImGui::TreePop(); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 06257e50f..cabdd5fd5 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6124,18 +6124,14 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags //------------------------------------------------------------------------- // [SECTION] Widgets: ListBox //------------------------------------------------------------------------- +// - BeginListBox() +// - EndListBox() // - ListBox() -// - ListBoxHeader() -// - ListBoxFooter() -//------------------------------------------------------------------------- -// FIXME: This is an old API. We should redesign some of it, rename ListBoxHeader->BeginListBox, ListBoxFooter->EndListBox -// and promote using them over existing ListBox() functions, similarly to how we now use combo boxes. //------------------------------------------------------------------------- -// FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature. // Tip: To have a list filling the entire window width, use size.x = -FLT_MIN and pass an non-visible label e.g. "##empty" // Tip: If your vertical size is calculated from an item count (e.g. 10 * item_height) consider adding a fractional part to facilitate seeing scrolling boundaries (e.g. 10.25 * item_height). -bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) +bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg) { ImGuiContext& g = *GImGui; ImGuiWindow* window = GetCurrentWindow(); @@ -6174,7 +6170,8 @@ bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg) return true; } -// FIXME: In principle this function should be called BeginListBox(). We should rename it after re-evaluating if we want to keep the same signature. +#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS +// OBSOLETED in 1.81 (from February 2021) bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items) { // If height_in_items == -1, default height is maximum 7. @@ -6183,15 +6180,15 @@ bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_item ImVec2 size; size.x = 0.0f; size.y = GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f; - return ListBoxHeader(label, size); + return BeginListBox(label, size); } +#endif -// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature. -void ImGui::ListBoxFooter() +void ImGui::EndListBox() { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched ListBoxHeader/ListBoxFooter calls. Did you test the return value of ListBoxHeader()?"); + IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched BeginListBox/EndListBox calls. Did you test the return value of BeginListBox?"); EndChildFrame(); EndGroup(); // This is only required to be able to do IsItemXXX query on the whole ListBox including label @@ -6203,14 +6200,23 @@ bool ImGui::ListBox(const char* label, int* current_item, const char* const item return value_changed; } +// This is merely a helper around BeginListBox(), EndListBox(). +// Considering using those directly to submit custom data or store selection differently. bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(void*, int, const char**), void* data, int items_count, int height_in_items) { - if (!ListBoxHeader(label, items_count, height_in_items)) + ImGuiContext& g = *GImGui; + + // Calculate size from "height_in_items" + if (height_in_items < 0) + height_in_items = ImMin(items_count, 7); + float height_in_items_f = height_in_items + 0.25f; + ImVec2 size(0.0f, ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f)); + + if (!BeginListBox(label, size)) return false; // Assume all items have even height (= 1 line of text). If you need items of different height, // you can create a custom version of ListBox() in your code without using the clipper. - ImGuiContext& g = *GImGui; bool value_changed = false; ImGuiListClipper clipper; clipper.Begin(items_count, GetTextLineHeightWithSpacing()); // We know exactly our line height here so we pass it as a minor optimization, but generally you don't need to. @@ -6232,7 +6238,7 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v SetItemDefaultFocus(); PopID(); } - ListBoxFooter(); + EndListBox(); if (value_changed) MarkItemEdited(g.CurrentWindow->DC.LastItemId); From 82a9b599ab60ed0adcdc018c9367e3fa43713701 Mon Sep 17 00:00:00 2001 From: Basil Fierz Date: Sat, 30 Jan 2021 20:25:20 +0100 Subject: [PATCH 14/18] Backend: webgpu: Fixes blending issue on Chrome 90+ and makes backend forward compatible with Emscripten 2.0.14 (#3632, #3770) --- backends/imgui_impl_wgpu.cpp | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index b18a53453..3be468c70 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -19,6 +19,8 @@ #include #include +#define HAS_EMSCRIPTEN_VERSION(major, minor, tiny) (__EMSCRIPTEN_major__ > (major) || (__EMSCRIPTEN_major__ == (major) && __EMSCRIPTEN_minor__ > (minor)) || (__EMSCRIPTEN_major__ == (major) && __EMSCRIPTEN_minor__ == (minor) && __EMSCRIPTEN_tiny__ >= (tiny))) + // Dear ImGui prototypes from imgui_internal.h extern ImGuiID ImHashData(const void* data_p, size_t data_size, ImU32 seed = 0); @@ -495,7 +497,7 @@ static void ImGui_ImplWGPU_CreateFontsTexture() textureCopyView.texture = g_resources.FontTexture; textureCopyView.mipLevel = 0; textureCopyView.origin = { 0, 0, 0 }; -#ifndef __EMSCRIPTEN__ +#if !defined(__EMSCRIPTEN__) || HAS_EMSCRIPTEN_VERSION(2, 0, 14) textureCopyView.aspect = WGPUTextureAspect_All; #endif @@ -522,6 +524,9 @@ static void ImGui_ImplWGPU_CreateFontsTexture() sampler_desc.addressModeU = WGPUAddressMode_Repeat; sampler_desc.addressModeV = WGPUAddressMode_Repeat; sampler_desc.addressModeW = WGPUAddressMode_Repeat; +#if !defined(__EMSCRIPTEN__) || HAS_EMSCRIPTEN_VERSION(2, 0, 14) + sampler_desc.maxAnisotropy = 1; +#endif g_resources.Sampler = wgpuDeviceCreateSampler(g_wgpuDevice, &sampler_desc); } @@ -559,15 +564,28 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() WGPUBindGroupLayoutEntry common_bg_layout_entries[2] = {}; common_bg_layout_entries[0].binding = 0; common_bg_layout_entries[0].visibility = WGPUShaderStage_Vertex; +#if !defined(__EMSCRIPTEN__) || HAS_EMSCRIPTEN_VERSION(2, 0, 14) + common_bg_layout_entries[0].buffer.type = WGPUBufferBindingType_Uniform; +#else common_bg_layout_entries[0].type = WGPUBindingType_UniformBuffer; +#endif common_bg_layout_entries[1].binding = 1; common_bg_layout_entries[1].visibility = WGPUShaderStage_Fragment; +#if !defined(__EMSCRIPTEN__) || HAS_EMSCRIPTEN_VERSION(2, 0, 14) + common_bg_layout_entries[1].sampler.type = WGPUSamplerBindingType_Filtering; +#else common_bg_layout_entries[1].type = WGPUBindingType_Sampler; +#endif WGPUBindGroupLayoutEntry image_bg_layout_entries[1] = {}; image_bg_layout_entries[0].binding = 0; image_bg_layout_entries[0].visibility = WGPUShaderStage_Fragment; +#if !defined(__EMSCRIPTEN__) || HAS_EMSCRIPTEN_VERSION(2, 0, 14) + image_bg_layout_entries[0].texture.sampleType = WGPUTextureSampleType_Float; + image_bg_layout_entries[0].texture.viewDimension = WGPUTextureViewDimension_2D; +#else image_bg_layout_entries[0].type = WGPUBindingType_SampledTexture; +#endif WGPUBindGroupLayoutDescriptor common_bg_layout_desc = {}; common_bg_layout_desc.entryCount = 2; @@ -620,8 +638,8 @@ bool ImGui_ImplWGPU_CreateDeviceObjects() { color_state.format = g_renderTargetFormat; color_state.alphaBlend.operation = WGPUBlendOperation_Add; - color_state.alphaBlend.srcFactor = WGPUBlendFactor_OneMinusSrcAlpha; - color_state.alphaBlend.dstFactor = WGPUBlendFactor_Zero; + color_state.alphaBlend.srcFactor = WGPUBlendFactor_SrcAlpha; + color_state.alphaBlend.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha; color_state.colorBlend.operation = WGPUBlendOperation_Add; color_state.colorBlend.srcFactor = WGPUBlendFactor_SrcAlpha; color_state.colorBlend.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha; From 58a0a7058c63e26917bfdfdfb7313475b66f4d28 Mon Sep 17 00:00:00 2001 From: ocornut Date: Wed, 3 Feb 2021 18:30:26 +0100 Subject: [PATCH 15/18] Backends: Using SetTexID() consistently instead of assigning to ->TexID. May make the later obsolete eventually. --- backends/imgui_impl_allegro5.cpp | 5 +++-- backends/imgui_impl_dx10.cpp | 4 ++-- backends/imgui_impl_dx11.cpp | 4 ++-- backends/imgui_impl_dx12.cpp | 4 ++-- backends/imgui_impl_dx9.cpp | 4 ++-- backends/imgui_impl_marmalade.cpp | 4 ++-- backends/imgui_impl_metal.mm | 4 ++-- backends/imgui_impl_opengl2.cpp | 4 ++-- backends/imgui_impl_opengl3.cpp | 4 ++-- backends/imgui_impl_vulkan.cpp | 2 +- backends/imgui_impl_wgpu.cpp | 4 ++-- imgui.cpp | 6 +++--- 12 files changed, 25 insertions(+), 24 deletions(-) diff --git a/backends/imgui_impl_allegro5.cpp b/backends/imgui_impl_allegro5.cpp index cadc4b7f2..db608e020 100644 --- a/backends/imgui_impl_allegro5.cpp +++ b/backends/imgui_impl_allegro5.cpp @@ -206,7 +206,7 @@ bool ImGui_ImplAllegro5_CreateDeviceObjects() return false; // Store our identifier - io.Fonts->TexID = (void*)cloned_img; + io.Fonts->SetTexID((void*)cloned_img); g_Texture = cloned_img; // Create an invisible mouse cursor @@ -222,8 +222,9 @@ void ImGui_ImplAllegro5_InvalidateDeviceObjects() { if (g_Texture) { + ImGuiIO& io = ImGui::GetIO(); + io.Fonts->SetTexID(NULL); al_destroy_bitmap(g_Texture); - ImGui::GetIO().Fonts->TexID = NULL; g_Texture = NULL; } if (g_MouseCursorInvisible) diff --git a/backends/imgui_impl_dx10.cpp b/backends/imgui_impl_dx10.cpp index 75db96a05..422f65290 100644 --- a/backends/imgui_impl_dx10.cpp +++ b/backends/imgui_impl_dx10.cpp @@ -305,7 +305,7 @@ static void ImGui_ImplDX10_CreateFontsTexture() } // Store our identifier - io.Fonts->TexID = (ImTextureID)g_pFontTextureView; + io.Fonts->SetTexID((ImTextureID)g_pFontTextureView); // Create texture sampler { @@ -482,7 +482,7 @@ void ImGui_ImplDX10_InvalidateDeviceObjects() return; if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; } - if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. + if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } diff --git a/backends/imgui_impl_dx11.cpp b/backends/imgui_impl_dx11.cpp index ebb8073c3..3edfeae69 100644 --- a/backends/imgui_impl_dx11.cpp +++ b/backends/imgui_impl_dx11.cpp @@ -317,7 +317,7 @@ static void ImGui_ImplDX11_CreateFontsTexture() } // Store our identifier - io.Fonts->TexID = (ImTextureID)g_pFontTextureView; + io.Fonts->SetTexID((ImTextureID)g_pFontTextureView); // Create texture sampler { @@ -494,7 +494,7 @@ void ImGui_ImplDX11_InvalidateDeviceObjects() return; if (g_pFontSampler) { g_pFontSampler->Release(); g_pFontSampler = NULL; } - if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. + if (g_pFontTextureView) { g_pFontTextureView->Release(); g_pFontTextureView = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } diff --git a/backends/imgui_impl_dx12.cpp b/backends/imgui_impl_dx12.cpp index 3f9f69653..39ca8f8df 100644 --- a/backends/imgui_impl_dx12.cpp +++ b/backends/imgui_impl_dx12.cpp @@ -395,7 +395,7 @@ static void ImGui_ImplDX12_CreateFontsTexture() // Store our identifier static_assert(sizeof(ImTextureID) >= sizeof(g_hFontSrvGpuDescHandle.ptr), "Can't pack descriptor handle into TexID, 32-bit not supported yet."); - io.Fonts->TexID = (ImTextureID)g_hFontSrvGpuDescHandle.ptr; + io.Fonts->SetTexID((ImTextureID)g_hFontSrvGpuDescHandle.ptr); } bool ImGui_ImplDX12_CreateDeviceObjects() @@ -640,7 +640,7 @@ void ImGui_ImplDX12_InvalidateDeviceObjects() SafeRelease(g_pFontTextureResource); ImGuiIO& io = ImGui::GetIO(); - io.Fonts->TexID = NULL; // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. + io.Fonts->SetTexID(NULL); // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. for (UINT i = 0; i < g_numFramesInFlight; i++) { diff --git a/backends/imgui_impl_dx9.cpp b/backends/imgui_impl_dx9.cpp index 0565ff4f6..2a575e81d 100644 --- a/backends/imgui_impl_dx9.cpp +++ b/backends/imgui_impl_dx9.cpp @@ -253,7 +253,7 @@ static bool ImGui_ImplDX9_CreateFontsTexture() g_FontTexture->UnlockRect(0); // Store our identifier - io.Fonts->TexID = (ImTextureID)g_FontTexture; + io.Fonts->SetTexID((ImTextureID)g_FontTexture); return true; } @@ -273,7 +273,7 @@ void ImGui_ImplDX9_InvalidateDeviceObjects() return; if (g_pVB) { g_pVB->Release(); g_pVB = NULL; } if (g_pIB) { g_pIB->Release(); g_pIB = NULL; } - if (g_FontTexture) { g_FontTexture->Release(); g_FontTexture = NULL; ImGui::GetIO().Fonts->TexID = NULL; } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. + if (g_FontTexture) { g_FontTexture->Release(); g_FontTexture = NULL; ImGui::GetIO().Fonts->SetTexID(NULL); } // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. } void ImGui_ImplDX9_NewFrame() diff --git a/backends/imgui_impl_marmalade.cpp b/backends/imgui_impl_marmalade.cpp index 805d0c3ea..c4f83a804 100644 --- a/backends/imgui_impl_marmalade.cpp +++ b/backends/imgui_impl_marmalade.cpp @@ -194,7 +194,7 @@ bool ImGui_Marmalade_CreateDeviceObjects() g_FontTexture->Upload(); // Store our identifier - io.Fonts->TexID = (ImTextureID)g_FontTexture; + io.Fonts->SetTexID((ImTextureID)g_FontTexture); return true; } @@ -209,8 +209,8 @@ void ImGui_Marmalade_InvalidateDeviceObjects() if (g_FontTexture) { + ImGui::GetIO().Fonts->SetTexID(0); delete g_FontTexture; - ImGui::GetIO().Fonts->TexID = 0; g_FontTexture = NULL; } } diff --git a/backends/imgui_impl_metal.mm b/backends/imgui_impl_metal.mm index d368daad7..b67c3ef3f 100644 --- a/backends/imgui_impl_metal.mm +++ b/backends/imgui_impl_metal.mm @@ -114,7 +114,7 @@ bool ImGui_ImplMetal_CreateFontsTexture(id device) [g_sharedMetalContext makeFontTextureWithDevice:device]; ImGuiIO& io = ImGui::GetIO(); - io.Fonts->TexID = (__bridge void *)g_sharedMetalContext.fontTexture; // ImTextureID == void* + io.Fonts->SetTexID((__bridge void *)g_sharedMetalContext.fontTexture); // ImTextureID == void* return (g_sharedMetalContext.fontTexture != nil); } @@ -123,7 +123,7 @@ void ImGui_ImplMetal_DestroyFontsTexture() { ImGuiIO& io = ImGui::GetIO(); g_sharedMetalContext.fontTexture = nil; - io.Fonts->TexID = nullptr; + io.Fonts->SetTexID(nullptr); } bool ImGui_ImplMetal_CreateDeviceObjects(id device) diff --git a/backends/imgui_impl_opengl2.cpp b/backends/imgui_impl_opengl2.cpp index cf860d7e1..1419e2d85 100644 --- a/backends/imgui_impl_opengl2.cpp +++ b/backends/imgui_impl_opengl2.cpp @@ -227,7 +227,7 @@ bool ImGui_ImplOpenGL2_CreateFontsTexture() glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Store our identifier - io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture; + io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontTexture); // Restore state glBindTexture(GL_TEXTURE_2D, last_texture); @@ -241,7 +241,7 @@ void ImGui_ImplOpenGL2_DestroyFontsTexture() { ImGuiIO& io = ImGui::GetIO(); glDeleteTextures(1, &g_FontTexture); - io.Fonts->TexID = 0; + io.Fonts->SetTexID(0); g_FontTexture = 0; } } diff --git a/backends/imgui_impl_opengl3.cpp b/backends/imgui_impl_opengl3.cpp index cd9e385c3..f3b2a937b 100644 --- a/backends/imgui_impl_opengl3.cpp +++ b/backends/imgui_impl_opengl3.cpp @@ -470,7 +470,7 @@ bool ImGui_ImplOpenGL3_CreateFontsTexture() glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels); // Store our identifier - io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontTexture; + io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontTexture); // Restore state glBindTexture(GL_TEXTURE_2D, last_texture); @@ -484,7 +484,7 @@ void ImGui_ImplOpenGL3_DestroyFontsTexture() { ImGuiIO& io = ImGui::GetIO(); glDeleteTextures(1, &g_FontTexture); - io.Fonts->TexID = 0; + io.Fonts->SetTexID(0); g_FontTexture = 0; } } diff --git a/backends/imgui_impl_vulkan.cpp b/backends/imgui_impl_vulkan.cpp index bae3b2b3a..44a555a5d 100644 --- a/backends/imgui_impl_vulkan.cpp +++ b/backends/imgui_impl_vulkan.cpp @@ -661,7 +661,7 @@ bool ImGui_ImplVulkan_CreateFontsTexture(VkCommandBuffer command_buffer) } // Store our identifier - io.Fonts->TexID = (ImTextureID)(intptr_t)g_FontImage; + io.Fonts->SetTexID((ImTextureID)(intptr_t)g_FontImage); return true; } diff --git a/backends/imgui_impl_wgpu.cpp b/backends/imgui_impl_wgpu.cpp index 3be468c70..089dbfd74 100644 --- a/backends/imgui_impl_wgpu.cpp +++ b/backends/imgui_impl_wgpu.cpp @@ -532,7 +532,7 @@ static void ImGui_ImplWGPU_CreateFontsTexture() // Store our identifier static_assert(sizeof(ImTextureID) >= sizeof(g_resources.FontTexture), "Can't pack descriptor handle into TexID, 32-bit not supported yet."); - io.Fonts->TexID = (ImTextureID)g_resources.FontTextureView; + io.Fonts->SetTexID((ImTextureID)g_resources.FontTextureView); } static void ImGui_ImplWGPU_CreateUniformBuffer() @@ -722,7 +722,7 @@ void ImGui_ImplWGPU_InvalidateDeviceObjects() SafeRelease(g_resources); ImGuiIO& io = ImGui::GetIO(); - io.Fonts->TexID = NULL; // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. + io.Fonts->SetTexID(NULL); // We copied g_pFontTextureView to io.Fonts->TexID so let's clear that as well. for (unsigned int i = 0; i < g_numFramesInFlight; i++) SafeRelease(g_pFrameResources[i]); diff --git a/imgui.cpp b/imgui.cpp index 2aeb49bec..48b6f8ca7 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -238,7 +238,7 @@ CODE // After we have created the texture, store its pointer/identifier (_in whichever format your engine uses_) in 'io.Fonts->TexID'. // This will be passed back to your via the renderer. Basically ImTextureID == void*. Read FAQ for details about ImTextureID. MyTexture* texture = MyEngine::CreateTextureFromMemoryPixels(pixels, width, height, TEXTURE_TYPE_RGBA32) - io.Fonts->TexID = (void*)texture; + io.Fonts->SetTexID((void*)texture); // Application main loop while (true) @@ -622,9 +622,9 @@ CODE - 2015/01/11 (1.30) - big font/image API change! now loads TTF file. allow for multiple fonts. no need for a PNG loader. - 2015/01/11 (1.30) - removed GetDefaultFontData(). uses io.Fonts->GetTextureData*() API to retrieve uncompressed pixels. - old: const void* png_data; unsigned int png_size; ImGui::GetDefaultFontData(NULL, NULL, &png_data, &png_size); [..Upload texture to GPU..]; - - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->TexId = YourTexIdentifier; + - new: unsigned char* pixels; int width, height; io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height); [..Upload texture to GPU..]; io.Fonts->SetTexID(YourTexIdentifier); you now have more flexibility to load multiple TTF fonts and manage the texture buffer for internal needs. It is now recommended that you sample the font texture with bilinear interpolation. - - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to set io.Fonts->TexID. + - 2015/01/11 (1.30) - added texture identifier in ImDrawCmd passed to your render function (we can now render images). make sure to call io.Fonts->SetTexID() - 2015/01/11 (1.30) - removed IO.PixelCenterOffset (unnecessary, can be handled in user projection matrix) - 2015/01/11 (1.30) - removed ImGui::IsItemFocused() in favor of ImGui::IsItemActive() which handles all widgets - 2014/12/10 (1.18) - removed SetNewWindowDefaultPos() in favor of new generic API SetNextWindowPos(pos, ImGuiSetCondition_FirstUseEver) From b898281e3c75d64ecc4e0f63aba0ec5e9182cce1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Fri, 5 Feb 2021 12:24:23 +0100 Subject: [PATCH 16/18] Demo: Added 'Examples->Fullscreen Window' demo. (#3789) + repack and zero-clear ImDrawData. --- docs/CHANGELOG.txt | 1 + examples/example_emscripten_wgpu/main.cpp | 2 +- imgui.h | 7 ++--- imgui_demo.cpp | 35 +++++++++++++++++++++-- 4 files changed, 37 insertions(+), 8 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index a1c61462b..d86103a43 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -78,6 +78,7 @@ Other Changes: - Log/Capture: Improved the ascii look of various widgets, making large dumps more easily human readable. - ImDrawList: Fixed AddCircle()/AddCircleFilled() with (rad > 0.0f && rad < 1.0f && num_segments == 0). (#3738) Would lead to a buffer read overflow. +- Demo: Added 'Examples->Fullscreen Window' demo. (#3789) - Backends: Win32: Dynamically loading XInput DLL instead of linking with it, facilite compiling with old WindowSDK versions or running on Windows 7. (#3646, #3645, #3248, #2716) [@Demonese] - Backends: Vulkan: Add support for custom Vulkan function loader and VK_NO_PROTOTYPES. (#3759, #3227) [@Hossein-Noroozpour] diff --git a/examples/example_emscripten_wgpu/main.cpp b/examples/example_emscripten_wgpu/main.cpp index 94f201429..b550f9dfc 100644 --- a/examples/example_emscripten_wgpu/main.cpp +++ b/examples/example_emscripten_wgpu/main.cpp @@ -75,7 +75,7 @@ int main(int, char**) //ImGui::StyleColorsClassic(); // Setup Platform/Renderer backends - ImGui_ImplGlfw_InitForVulkan(window, true); + ImGui_ImplGlfw_InitForWebGPU(window, true); ImGui_ImplWGPU_Init(wgpu_device, 3, WGPUTextureFormat_RGBA8Unorm); // Load Fonts diff --git a/imgui.h b/imgui.h index 477a3c6cb..5ffc3ec7e 100644 --- a/imgui.h +++ b/imgui.h @@ -2461,18 +2461,17 @@ struct ImDrawList struct ImDrawData { bool Valid; // Only valid after Render() is called and before the next NewFrame() is called. - ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. int CmdListsCount; // Number of ImDrawList* to render int TotalIdxCount; // For convenience, sum of all ImDrawList's IdxBuffer.Size int TotalVtxCount; // For convenience, sum of all ImDrawList's VtxBuffer.Size + ImDrawList** CmdLists; // Array of ImDrawList* to render. The ImDrawList are owned by ImGuiContext and only pointed to from here. ImVec2 DisplayPos; // Upper-left position of the viewport to render (== upper-left of the orthogonal projection matrix to use) ImVec2 DisplaySize; // Size of the viewport to render (== io.DisplaySize for the main viewport) (DisplayPos + DisplaySize == lower-right of the orthogonal projection matrix to use) ImVec2 FramebufferScale; // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display. // Functions - ImDrawData() { Valid = false; Clear(); } - ~ImDrawData() { Clear(); } - void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.f, 0.f); } // The ImDrawList are owned by ImGuiContext! + ImDrawData() { Clear(); } + void Clear() { memset(this, 0, sizeof(*this)); } // The ImDrawList are owned by ImGuiContext! IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering! IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution. }; diff --git a/imgui_demo.cpp b/imgui_demo.cpp index 55a85cda4..bd6533a85 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -63,8 +63,9 @@ Index of this file: // [SECTION] Example App: Long Text / ShowExampleAppLongText() // [SECTION] Example App: Auto Resize / ShowExampleAppAutoResize() // [SECTION] Example App: Constrained Resize / ShowExampleAppConstrainedResize() -// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() -// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() +// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() +// [SECTION] Example App: Manipulating window titles / ShowExampleAppWindowTitles() // [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering() // [SECTION] Example App: Documents Handling / ShowExampleAppDocuments() @@ -168,6 +169,7 @@ static void ShowExampleAppLongText(bool* p_open); static void ShowExampleAppAutoResize(bool* p_open); static void ShowExampleAppConstrainedResize(bool* p_open); static void ShowExampleAppSimpleOverlay(bool* p_open); +static void ShowExampleAppFullscreen(bool* p_open); static void ShowExampleAppWindowTitles(bool* p_open); static void ShowExampleAppCustomRendering(bool* p_open); static void ShowExampleMenuFile(); @@ -259,6 +261,7 @@ void ImGui::ShowDemoWindow(bool* p_open) static bool show_app_auto_resize = false; static bool show_app_constrained_resize = false; static bool show_app_simple_overlay = false; + static bool show_app_fullscreen = false; static bool show_app_window_titles = false; static bool show_app_custom_rendering = false; @@ -273,6 +276,7 @@ void ImGui::ShowDemoWindow(bool* p_open) if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay); + if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen); if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering); @@ -354,6 +358,7 @@ void ImGui::ShowDemoWindow(bool* p_open) ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize); ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize); ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay); + ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen); ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles); ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); ImGui::MenuItem("Documents", NULL, &show_app_documents); @@ -6971,7 +6976,7 @@ static void ShowExampleAppConstrainedResize(bool* p_open) } //----------------------------------------------------------------------------- -// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay() +// [SECTION] Example App: Simple overlay / ShowExampleAppSimpleOverlay() //----------------------------------------------------------------------------- // Demonstrate creating a simple static window with no decoration @@ -7012,6 +7017,30 @@ static void ShowExampleAppSimpleOverlay(bool* p_open) ImGui::End(); } +//----------------------------------------------------------------------------- +// [SECTION] Example App: Fullscreen window / ShowExampleAppFullscreen() +//----------------------------------------------------------------------------- + +// Demonstrate creating a window covering the entire screen/viewport +static void ShowExampleAppFullscreen(bool* p_open) +{ + ImGuiIO& io = ImGui::GetIO(); + static ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings; + ImGui::SetNextWindowPos(ImVec2(0, 0)); + ImGui::SetNextWindowSize(io.DisplaySize); + if (ImGui::Begin("Example: Fullscreen window", p_open, flags)) + { + ImGui::CheckboxFlags("ImGuiWindowFlags_NoBackground", &flags, ImGuiWindowFlags_NoBackground); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoDecoration", &flags, ImGuiWindowFlags_NoDecoration); + ImGui::Indent(); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoTitleBar", &flags, ImGuiWindowFlags_NoTitleBar); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoCollapse", &flags, ImGuiWindowFlags_NoCollapse); + ImGui::CheckboxFlags("ImGuiWindowFlags_NoScrollbar", &flags, ImGuiWindowFlags_NoScrollbar); + ImGui::Unindent(); + } + ImGui::End(); +} + //----------------------------------------------------------------------------- // [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles() //----------------------------------------------------------------------------- From 03038df1cc018d80fb0307416fb24de0eaf41a99 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Feb 2021 14:03:24 +0100 Subject: [PATCH 17/18] ImDrawList: fix divide by zero (for which result was unused but triggering on some archs/setup) added by f144c67676 (#3738) --- imgui_draw.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index 213ac4478..c316384e8 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -384,7 +384,7 @@ void ImDrawListSharedData::SetCircleSegmentMaxError(float max_error) for (int i = 0; i < IM_ARRAYSIZE(CircleSegmentCounts); i++) { const float radius = (float)i; - const int segment_count = IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError); + const int segment_count = (i > 0) ? IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, CircleSegmentMaxError) : 0; CircleSegmentCounts[i] = (ImU8)ImMin(segment_count, 255); } } From 56f7bdae9955ac31864e71be70a41cb57e5818c1 Mon Sep 17 00:00:00 2001 From: ocornut Date: Mon, 8 Feb 2021 16:37:51 +0100 Subject: [PATCH 18/18] ImDrawList: Clarified PathArcTo() need for a_min <= a_max with an assert. Fixed PathArcToFast() handling of a_min > a_max. --- docs/CHANGELOG.txt | 12 +++++++----- imgui.h | 6 +++--- imgui_demo.cpp | 7 ++++--- imgui_draw.cpp | 4 +++- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index d86103a43..3913f5cf8 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -37,10 +37,10 @@ HOW TO UPDATE? Breaking Changes: -- ListBox helpers: +- ListBox helpers: - Renamed ListBoxHeader(const char* label, ImVec2 size) to BeginListBox(). - Renamed ListBoxFooter() to EndListBox(). - - Removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. + - Removed ListBoxHeader(const char* label, int items_count, int height_in_items = -1) in favor of specifying size. In the redirection function, made vertical padding consistent regardless of (items_count <= height_in_items) or not. - Kept inline redirection function for all threes (will obsolete). - imgui_freetype: @@ -67,7 +67,7 @@ Other Changes: other than compiling misc/freetype/imgui_freetype.cpp and linking with FreeType. - Use '#define IMGUI_ENABLE_STB_TRUETYPE' if you somehow need the stb_truetype rasterizer to be compiled in along with the FreeType one, otherwise it is enabled by default. -- Fonts: imgui_freetype: Added support for colored glyphs as supported by Freetype 2.10+ (for .ttf using CPAL/COLR +- Fonts: imgui_freetype: Added support for colored glyphs as supported by Freetype 2.10+ (for .ttf using CPAL/COLR tables only). Enable the ImGuiFreeTypeBuilderFlags_LoadColor on a given font. Atlas always output directly as RGBA8 in this situation. Likely to make sense with IMGUI_USE_WCHAR32. (#3369) [@pshurgal] - Fonts: Fixed CalcTextSize() width rounding so it behaves more like a ceil. This is in order for text wrapping @@ -78,6 +78,8 @@ Other Changes: - Log/Capture: Improved the ascii look of various widgets, making large dumps more easily human readable. - ImDrawList: Fixed AddCircle()/AddCircleFilled() with (rad > 0.0f && rad < 1.0f && num_segments == 0). (#3738) Would lead to a buffer read overflow. +- ImDrawList: Clarified PathArcTo() need for a_min <= a_max with an assert. +- ImDrawList: Fixed PathArcToFast() handling of a_min > a_max. - Demo: Added 'Examples->Fullscreen Window' demo. (#3789) - Backends: Win32: Dynamically loading XInput DLL instead of linking with it, facilite compiling with old WindowSDK versions or running on Windows 7. (#3646, #3645, #3248, #2716) [@Demonese] @@ -88,8 +90,8 @@ Other Changes: - Backends: WebGPU: Added enderer backend for WebGPU support (imgui_impl_wgpu.cpp) (#3632) [@bfierz] Please note that WebGPU is currently experimental, will not run on non-beta browsers, and may break. - Examples: WebGPU: Added Emscripten+WebGPU example. (#3632) [@bfierz] -- Backends: GLFW: Added ImGui_ImplGlfw_InitForWebGPU() init point. It currently has strictly no effect on anything, - but because some multi-viewport renderers require knowledge of the render stack in the Platform back-end, we're +- Backends: GLFW: Added ImGui_ImplGlfw_InitForWebGPU() init point. It currently has strictly no effect on anything, + but because some multi-viewport renderers require knowledge of the render stack in the Platform back-end, we're adding it for consistency. (#3632) diff --git a/imgui.h b/imgui.h index 5ffc3ec7e..627fc37ae 100644 --- a/imgui.h +++ b/imgui.h @@ -2409,9 +2409,9 @@ struct ImDrawList inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order. inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; } IMGUI_API void PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 10); - IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle - IMGUI_API void PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); // Cubic Bezier (4 control points) - IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points) + IMGUI_API void PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle + IMGUI_API void PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); // Cubic Bezier (4 control points) + IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points) IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); // Advanced diff --git a/imgui_demo.cpp b/imgui_demo.cpp index bd6533a85..91b39d7ac 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -7130,7 +7130,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) static bool curve_segments_override = false; static int curve_segments_override_v = 8; static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f); - ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f"); + ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 100.0f, "%.0f"); ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f"); ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12); ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override); @@ -7147,6 +7147,7 @@ static void ShowExampleAppCustomRendering(bool* p_open) const ImDrawCornerFlags corners_none = 0; const ImDrawCornerFlags corners_all = ImDrawCornerFlags_All; const ImDrawCornerFlags corners_tl_br = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight; + const float rounding = sz / 5.0f; const int circle_segments = circle_segments_override ? circle_segments_override_v : 0; const int curve_segments = curve_segments_override ? curve_segments_override_v : 0; float x = p.x + 4.0f; @@ -7158,8 +7159,8 @@ static void ShowExampleAppCustomRendering(bool* p_open) draw_list->AddNgon(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, ngon_sides, th); x += sz + spacing; // N-gon draw_list->AddCircle(ImVec2(x + sz*0.5f, y + sz*0.5f), sz*0.5f, col, circle_segments, th); x += sz + spacing; // Circle draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 0.0f, corners_none, th); x += sz + spacing; // Square - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_all, th); x += sz + spacing; // Square with all rounded corners - draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, 10.0f, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_all, th); x += sz + spacing; // Square with all rounded corners + draw_list->AddRect(ImVec2(x, y), ImVec2(x + sz, y + sz), col, rounding, corners_tl_br, th); x += sz + spacing; // Square with two rounded corners draw_list->AddTriangle(ImVec2(x+sz*0.5f,y), ImVec2(x+sz, y+sz-0.5f), ImVec2(x, y+sz-0.5f), col, th);x += sz + spacing; // Triangle //draw_list->AddTriangle(ImVec2(x+sz*0.2f,y), ImVec2(x, y+sz-0.5f), ImVec2(x+sz*0.4f, y+sz-0.5f), col, th);x+= sz*0.4f + spacing; // Thin triangle draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!) diff --git a/imgui_draw.cpp b/imgui_draw.cpp index c316384e8..6b1ccd0e0 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1018,11 +1018,12 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12) { - if (radius == 0.0f || a_min_of_12 > a_max_of_12) + if (radius == 0.0f) { _Path.push_back(center); return; } + IM_ASSERT(a_min_of_12 <= a_max_of_12); // For legacy reason the PathArcToFast() always takes angles where 2*PI is represented by 12, // but it is possible to set IM_DRAWLIST_ARCFAST_TESSELATION_MULTIPLIER to a higher value. This should compile to a no-op otherwise. @@ -1046,6 +1047,7 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa _Path.push_back(center); return; } + IM_ASSERT(a_min <= a_max); // Note that we are adding a point at both a_min and a_max. // If you are trying to draw a full closed circle you don't want the overlapping points!