1
0
Fork 0
mirror of https://github.com/ocornut/imgui.git synced 2026-01-21 01:44:21 +00:00

Merge branch 'ocornut:master' into ImVec-UB-and-Unreachable

This commit is contained in:
brayden 2025-12-22 13:27:22 -05:00 committed by GitHub
commit 4767c739a7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 136 additions and 47 deletions

View file

@ -67,6 +67,10 @@ Other Changes:
- Fonts:
- Fixed an issue related to EllipsisChar handling, while changing
font loader or font loader flags dynamically in Style->Fonts menus.
- imgui_freetype: fixed overwriting ImFontConfig::PixelSnapH when hinting
is enabled, creating side-effects when later disabling hinting or
dynamically switching to stb_truetype rasterizer.
which would prevent
- Textures:
- Fixed a building issue when ImTextureID is defined as a struct.
- Fixed displaying texture # in Metrics/Debugger window.
@ -93,11 +97,18 @@ Other Changes:
- Added ImGuiSliderFlags_ColorMarkers to opt-in adding R/G/B/A color markers
next to each components, in multi-components functions.
- Added a way to select a specific marker color.
- Text:
- Text, InputText:
- Reworked word-wrapping logic:
- Try to not wrap in the middle of contiguous punctuations. (#8139, #8439, #9094)
- Try to not wrap between a punctuation and a digit. (#8503)
- Inside InputTextMultiline() with _WordWrap: prefer keeping blanks at the
end of a line rather than at the beginning of next line. (#8990, #3237)
- Fixed low-level word-wrapping function reading from *text_end when passed
a string range. (#9107) [@achabense]
- Scrollbar: fixed a codepath leading to a divide-by-zero (which would not be
noticeable by user but detected by sanitizers). (#9089) [@judicaelclair]
- Added GetItemFlags() in public API for consistency and to expose generic
flags of last submitted item. (#9127)
- Debug Tools:
- Debug Log: fixed incorrectly printing characters in IO log when submitting
non-ASCII values to io.AddInputCharacter(). (#9099)

View file

@ -6330,6 +6330,12 @@ ImVec2 ImGui::GetItemRectSize()
return g.LastItemData.Rect.GetSize();
}
ImGuiItemFlags ImGui::GetItemFlags()
{
ImGuiContext& g = *GImGui;
return g.LastItemData.ItemFlags;
}
// Prior to v1.90 2023/10/16, the BeginChild() function took a 'bool border = false' parameter instead of 'ImGuiChildFlags child_flags = 0'.
// ImGuiChildFlags_Borders is defined as always == 1 in order to allow old code passing 'true'. Read comments in imgui.h for details!
bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags)

View file

@ -30,7 +30,7 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.92.6 WIP"
#define IMGUI_VERSION_NUM 19256
#define IMGUI_VERSION_NUM 19257
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
@ -1025,6 +1025,7 @@ namespace ImGui
IMGUI_API ImVec2 GetItemRectMin(); // get upper-left bounding rectangle of the last item (screen space)
IMGUI_API ImVec2 GetItemRectMax(); // get lower-right bounding rectangle of the last item (screen space)
IMGUI_API ImVec2 GetItemRectSize(); // get size of last item
IMGUI_API ImGuiItemFlags GetItemFlags(); // get generic flags of last item
// Viewports
// - Currently represents the Platform Window created by the application which is hosting our Dear ImGui windows.
@ -1226,7 +1227,7 @@ enum ImGuiChildFlags_
};
// Flags for ImGui::PushItemFlag()
// (Those are shared by all items)
// (Those are shared by all submitted items)
enum ImGuiItemFlags_
{
ImGuiItemFlags_None = 0, // (Default)
@ -1236,6 +1237,7 @@ enum ImGuiItemFlags_
ImGuiItemFlags_ButtonRepeat = 1 << 3, // false // Any button-like behavior will have repeat mode enabled (based on io.KeyRepeatDelay and io.KeyRepeatRate values). Note that you can also call IsItemActive() after any button to tell if it is being held.
ImGuiItemFlags_AutoClosePopups = 1 << 4, // true // MenuItem()/Selectable() automatically close their parent popup window.
ImGuiItemFlags_AllowDuplicateId = 1 << 5, // false // Allow submitting an item with the same identifier as an item already submitted this frame without triggering a warning tooltip if io.ConfigDebugHighlightIdConflicts is set.
ImGuiItemFlags_Disabled = 1 << 6, // false // [Internal] Disable interactions. DOES NOT affect visuals. This is used by BeginDisabled()/EndDisabled() and only provided here so you can read back via GetItemFlags().
};
// Flags for ImGui::InputText()

View file

@ -17,7 +17,7 @@ Index of this file:
// [SECTION] ImFontAtlas: backend for stb_truetype
// [SECTION] ImFontAtlas: glyph ranges helpers
// [SECTION] ImFontGlyphRangesBuilder
// [SECTION] ImFont
// [SECTION] ImFontBaked, ImFont
// [SECTION] ImGui Internal Render Helpers
// [SECTION] Decompression code
// [SECTION] Default font data (ProggyClean.ttf)
@ -3392,6 +3392,7 @@ void ImFontAtlasBuildMain(ImFontAtlas* atlas)
void ImFontAtlasBuildGetOversampleFactors(ImFontConfig* src, ImFontBaked* baked, int* out_oversample_h, int* out_oversample_v)
{
// (Only used by stb_truetype builder)
// Automatically disable horizontal oversampling over size 36
const float raster_size = baked->Size * baked->RasterizerDensity * src->RasterizerDensity;
*out_oversample_h = (src->OversampleH != 0) ? src->OversampleH : (raster_size > 36.0f || src->PixelSnapH) ? 1 : 2;
@ -4234,6 +4235,10 @@ void ImFontAtlasBuildInit(ImFontAtlas* atlas)
ImFontAtlasUpdateDrawListsSharedData(atlas);
//atlas->TexIsBuilt = true;
// Lazily initialize char/text classifier
// FIXME: This could be practically anywhere, and should eventually be parameters to CalcTextSize/word-wrapping code, but there's no obvious spot now.
ImTextInitClassifiers();
}
// Destroy builder and all cached glyphs. Do not destroy actual fonts.
@ -5068,7 +5073,7 @@ void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
}
//-----------------------------------------------------------------------------
// [SECTION] ImFont
// [SECTION] ImFontBaked, ImFont
//-----------------------------------------------------------------------------
ImFontBaked::ImFontBaked()
@ -5371,17 +5376,64 @@ const char* ImTextCalcWordWrapNextLineStart(const char* text, const char* text_e
return text;
}
void ImTextClassifierClear(ImU32* bits, unsigned int codepoint_min, unsigned int codepoint_end, ImWcharClass char_class)
{
for (unsigned int c = codepoint_min; c < codepoint_end; c++)
ImTextClassifierSetCharClass(bits, codepoint_min, codepoint_end, char_class, c);
}
void ImTextClassifierSetCharClass(ImU32* bits, unsigned int codepoint_min, unsigned int codepoint_end, ImWcharClass char_class, unsigned int c)
{
IM_ASSERT(c >= codepoint_min && c < codepoint_end);
IM_UNUSED(codepoint_end);
c -= codepoint_min;
const ImU32 shift = (c & 15) << 1;
bits[c >> 4] = (bits[c >> 4] & ~(0x03 << shift)) | (char_class << shift);
}
void ImTextClassifierSetCharClassFromStr(ImU32* bits, unsigned int codepoint_min, unsigned int codepoint_end, ImWcharClass char_class, const char* s)
{
const char* s_end = s + strlen(s);
while (*s)
{
unsigned int c;
s += ImTextCharFromUtf8(&c, s, s_end);
ImTextClassifierSetCharClass(bits, codepoint_min, codepoint_end, char_class, c);
}
}
#define ImTextClassifierGet(_BITS, _CHAR_OFFSET) ((_BITS[(_CHAR_OFFSET) >> 4] >> (((_CHAR_OFFSET) & 15) << 1)) & 0x03)
// 2-bit per character
static ImU32 g_CharClassifierIsSeparator_0000_007f[128 / 16] = {};
static ImU32 g_CharClassifierIsSeparator_3000_300f[ 16 / 16] = {};
void ImTextInitClassifiers()
{
if (ImTextClassifierGet(g_CharClassifierIsSeparator_0000_007f, ',') != 0)
return;
// List of hardcoded separators: .,;!?'"
// Making this dynamic given known ranges is trivial BUT requires us to standardize where you pass them as parameters. (#3002, #8503)
ImTextClassifierClear(g_CharClassifierIsSeparator_0000_007f, 0, 128, ImWcharClass_Other);
ImTextClassifierSetCharClassFromStr(g_CharClassifierIsSeparator_0000_007f, 0, 128, ImWcharClass_Blank, " \t");
ImTextClassifierSetCharClassFromStr(g_CharClassifierIsSeparator_0000_007f, 0, 128, ImWcharClass_Punct, ".,;!?\"");
ImTextClassifierClear(g_CharClassifierIsSeparator_3000_300f, 0x3000, 0x300F, ImWcharClass_Other);
ImTextClassifierSetCharClass(g_CharClassifierIsSeparator_3000_300f, 0x3000, 0x300F, ImWcharClass_Blank, 0x3000);
ImTextClassifierSetCharClass(g_CharClassifierIsSeparator_3000_300f, 0x3000, 0x300F, ImWcharClass_Punct, 0x3001);
ImTextClassifierSetCharClass(g_CharClassifierIsSeparator_3000_300f, 0x3000, 0x300F, ImWcharClass_Punct, 0x3002);
}
// Simple word-wrapping for English, not full-featured. Please submit failing cases!
// This will return the next location to wrap from. If no wrapping if necessary, this will fast-forward to e.g. text_end.
// FIXME: Much possible improvements (don't cut things like "word !", "word!!!" but cut within "word,,,,", more sensible support for punctuations, support for Unicode punctuations, etc.)
// Refer to imgui_test_suite's "drawlist_text_wordwrap_1" for tests.
const char* ImFontCalcWordWrapPositionEx(ImFont* font, float size, const char* text, const char* text_end, float wrap_width, ImDrawTextFlags flags)
{
// For references, possible wrap point marked with ^
// "aaa bbb, ccc,ddd. eee fff. ggg!"
// ^ ^ ^ ^ ^__ ^ ^
// List of hardcoded separators: .,;!?'"
// Skip extra blanks after a line returns (that includes not counting them in width computation)
// e.g. "Hello world" --> "Hello" "World"
@ -5392,16 +5444,20 @@ const char* ImFontCalcWordWrapPositionEx(ImFont* font, float size, const char* t
const float scale = size / baked->Size;
float line_width = 0.0f;
float word_width = 0.0f;
float blank_width = 0.0f;
wrap_width /= scale; // We work with unscaled widths to avoid scaling every characters
const char* word_end = text;
const char* prev_word_end = NULL;
bool inside_word = true;
const char* s = text;
IM_ASSERT(text_end != NULL);
int prev_type = ImWcharClass_Other;
const bool keep_blanks = (flags & ImDrawTextFlags_WrapKeepBlanks) != 0;
// Find next wrapping point
//const char* span_begin = s;
const char* span_end = s;
float span_width = 0.0f;
while (s < text_end)
{
unsigned int c = (unsigned int)*s;
@ -5417,7 +5473,7 @@ const char* ImFontCalcWordWrapPositionEx(ImFont* font, float size, const char* t
return s; // Direct return, skip "Wrap_width is too small to fit anything" path.
if (c == '\r')
{
s = next_s;
s = next_s; // Fast-skip
continue;
}
}
@ -5427,46 +5483,56 @@ const char* ImFontCalcWordWrapPositionEx(ImFont* font, float size, const char* t
if (char_width < 0.0f)
char_width = BuildLoadGlyphGetAdvanceOrFallback(baked, c);
if (ImCharIsBlankW(c))
// Classify current character
int curr_type;
if (c < 128)
curr_type = ImTextClassifierGet(g_CharClassifierIsSeparator_0000_007f, c);
else if (c >= 0x3000 && c < 0x3010)
curr_type = ImTextClassifierGet(g_CharClassifierIsSeparator_3000_300f, c & 15); //-V578
else
curr_type = ImWcharClass_Other;
if (curr_type == ImWcharClass_Blank)
{
if (inside_word)
// End span: 'A ' or '. '
if (prev_type != ImWcharClass_Blank && !keep_blanks)
{
line_width += blank_width;
blank_width = 0.0f;
word_end = s;
span_end = s;
line_width += span_width;
span_width = 0.0f;
}
blank_width += char_width;
inside_word = false;
}
else
{
word_width += char_width;
if (inside_word)
// End span: '.X' unless X is a digit
if (prev_type == ImWcharClass_Punct && curr_type != ImWcharClass_Punct && !(c >= '0' && c <= '9')) // FIXME: Digit checks might be removed if allow custom separators (#8503)
{
word_end = next_s;
span_end = s;
line_width += span_width + blank_width;
span_width = blank_width = 0.0f;
}
else
// End span: 'A ' or '. '
else if (prev_type == ImWcharClass_Blank && keep_blanks)
{
prev_word_end = word_end;
line_width += word_width + blank_width;
if ((flags & ImDrawTextFlags_WrapKeepBlanks) && line_width <= wrap_width)
prev_word_end = s;
word_width = blank_width = 0.0f;
span_end = s;
line_width += span_width + blank_width;
span_width = blank_width = 0.0f;
}
// Allow wrapping after punctuation.
inside_word = (c != '.' && c != ',' && c != ';' && c != '!' && c != '?' && c != '\"' && c != 0x3001 && c != 0x3002);
span_width += char_width;
}
// We ignore blank width at the end of the line (they can be skipped)
if (line_width + word_width > wrap_width)
if (span_width + blank_width + line_width > wrap_width)
{
// Words that cannot possibly fit within an entire line will be cut anywhere.
if (word_width < wrap_width)
s = prev_word_end ? prev_word_end : word_end;
break;
if (span_width + blank_width > wrap_width)
break;
// FIXME: Narrow wrapping e.g. "A quick brown" -> "Quic|k br|own", would require knowing if span is going to be longer than wrap_width.
//if (span_width > wrap_width && !is_blank && !was_blank)
// return s;
return span_end;
}
prev_type = curr_type;
s = next_s;
}

View file

@ -441,6 +441,16 @@ IMGUI_API ImVec2 ImFontCalcTextSizeEx(ImFont* font, float size, float max
IMGUI_API const char* ImFontCalcWordWrapPositionEx(ImFont* font, float size, const char* text, const char* text_end, float wrap_width, ImDrawTextFlags flags = 0);
IMGUI_API const char* ImTextCalcWordWrapNextLineStart(const char* text, const char* text_end, ImDrawTextFlags flags = 0); // trim trailing space and find beginning of next line
// Character classification for word-wrapping logic
enum ImWcharClass
{
ImWcharClass_Blank, ImWcharClass_Punct, ImWcharClass_Other
};
IMGUI_API void ImTextInitClassifiers();
IMGUI_API void ImTextClassifierClear(ImU32* bits, unsigned int codepoint_min, unsigned int codepoint_end, ImWcharClass char_class);
IMGUI_API void ImTextClassifierSetCharClass(ImU32* bits, unsigned int codepoint_min, unsigned int codepoint_end, ImWcharClass char_class, unsigned int c);
IMGUI_API void ImTextClassifierSetCharClassFromStr(ImU32* bits, unsigned int codepoint_min, unsigned int codepoint_end, ImWcharClass char_class, const char* s);
// Helpers: File System
#ifdef IMGUI_DISABLE_FILE_FUNCTIONS
#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS
@ -955,7 +965,6 @@ enum ImGuiDataTypePrivate_
enum ImGuiItemFlagsPrivate_
{
// Controlled by user
ImGuiItemFlags_Disabled = 1 << 10, // false // Disable interactions (DOES NOT affect visuals. DO NOT mix direct use of this with BeginDisabled(). See BeginDisabled()/EndDisabled() for full disable feature, and github #211).
ImGuiItemFlags_ReadOnly = 1 << 11, // false // [ALPHA] Allow hovering interactions but underlying value is not changed.
ImGuiItemFlags_MixedValue = 1 << 12, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets)
ImGuiItemFlags_NoWindowHoverableCheck = 1 << 13, // false // Disable hoverable check in ItemHoverable()
@ -3251,7 +3260,6 @@ namespace ImGui
// Basic Accessors
inline ImGuiItemStatusFlags GetItemStatusFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.StatusFlags; }
inline ImGuiItemFlags GetItemFlags() { ImGuiContext& g = *GImGui; return g.LastItemData.ItemFlags; }
inline ImGuiID GetActiveID() { ImGuiContext& g = *GImGui; return g.ActiveId; }
inline ImGuiID GetFocusID() { ImGuiContext& g = *GImGui; return g.NavId; }
IMGUI_API void SetActiveID(ImGuiID id, ImGuiWindow* window);

View file

@ -153,7 +153,7 @@ struct ImGui_ImplFreeType_Data
struct ImGui_ImplFreeType_FontSrcData
{
// Initialize from an external data buffer. Doesn't copy data, and you must ensure it stays valid up to this object lifetime.
bool InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeLoaderFlags extra_user_flags);
bool InitFont(FT_Library ft_library, const ImFontConfig* src, ImGuiFreeTypeLoaderFlags extra_user_flags);
void CloseFont();
ImGui_ImplFreeType_FontSrcData() { memset((void*)this, 0, sizeof(*this)); }
~ImGui_ImplFreeType_FontSrcData() { CloseFont(); }
@ -172,7 +172,7 @@ struct ImGui_ImplFreeType_FontSrcBakedData
ImGui_ImplFreeType_FontSrcBakedData() { memset((void*)this, 0, sizeof(*this)); }
};
bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfig* src, ImGuiFreeTypeLoaderFlags extra_font_loader_flags)
bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, const ImFontConfig* src, ImGuiFreeTypeLoaderFlags extra_font_loader_flags)
{
FT_Error error = FT_New_Memory_Face(ft_library, (const FT_Byte*)src->FontData, (FT_Long)src->FontDataSize, (FT_Long)src->FontNo, &FtFace);
if (error != 0)
@ -187,12 +187,8 @@ bool ImGui_ImplFreeType_FontSrcData::InitFont(FT_Library ft_library, ImFontConfi
LoadFlags = 0;
if ((UserFlags & ImGuiFreeTypeLoaderFlags_Bitmap) == 0)
LoadFlags |= FT_LOAD_NO_BITMAP;
if (UserFlags & ImGuiFreeTypeLoaderFlags_NoHinting)
LoadFlags |= FT_LOAD_NO_HINTING;
else
src->PixelSnapH = true; // FIXME: A bit weird to do this this way.
if (UserFlags & ImGuiFreeTypeLoaderFlags_NoAutoHint)
LoadFlags |= FT_LOAD_NO_AUTOHINT;
if (UserFlags & ImGuiFreeTypeLoaderFlags_ForceAutoHint)
@ -543,7 +539,7 @@ static bool ImGui_ImplFreeType_FontBakedLoadGlyph(ImFontAtlas* atlas, ImFontConf
const float offsets_scale = (ref_size != 0.0f) ? (baked->Size / ref_size) : 1.0f;
float font_off_x = (src->GlyphOffset.x * offsets_scale);
float font_off_y = (src->GlyphOffset.y * offsets_scale) + baked->Ascent;
if (src->PixelSnapH) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome.
if (src->PixelSnapH || (bd_font_data->UserFlags & ImGuiFreeTypeLoaderFlags_NoHinting) == 0) // Snap scaled offset. This is to mitigate backward compatibility issues for GlyphOffset, but a better design would be welcome.
font_off_x = IM_ROUND(font_off_x);
if (src->PixelSnapV)
font_off_y = IM_ROUND(font_off_y);