diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index e0d1b70d8..672c24c30 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -84,6 +84,8 @@ Other Changes: hasn't been owned by another items. This is more correct and also necessary to avoid Drags/Sliders cancelling also triggering a cancel menu. (#8564, #9534) - ImGuiTextFilter: + - Fixed filtering when mixing "include" and "-exclude" keyword so that an "-exclude" + match always filters out. (#2435) [@kudaba, @ocornut] - Added `DrawWithHint()` function. (#6206, #6395, #6447) - Added a "incl,-excl" hint by default when the search field is empty. (#6206, #6395, #6447) - Style: diff --git a/imgui.cpp b/imgui.cpp index b2bdf55f0..8968a8f3f 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -3116,74 +3116,69 @@ bool ImGuiTextFilter::DrawWithHint(const char* label, const char* hint) return value_changed; } -static void ImStrSplit(const char* b, const char* e, char separator, ImVector* out) +static void ImGuiTextFilter_BuildAddItem(ImGuiTextFilter* f, const char* word_b, const char* word_e) { - out->resize(0); - const char* wb = b; - const char* we = wb; - while (we < e) - { - if (*we == separator) - { - out->push_back(ImGuiTextFilter::ImGuiTextFilterItem(wb, we)); - wb = we + 1; - } - we++; - } - if (wb != we) - out->push_back(ImGuiTextFilter::ImGuiTextFilterItem(wb, we)); + // Trim (FIXME: UTF-8 support?) + while (word_b < word_e && ImCharIsBlankA(word_b[0])) + word_b++; + while (word_e > word_b && ImCharIsBlankA(word_e[-1])) + word_e--; + if (word_e - word_b <= 0) + return; + + // Add to list + // FIXME-OPT: on push_front(): as N is derived from user inputs we expect this to be fine. + const bool is_excl = (word_b[0] == '-'); + f->_Items.insert(is_excl ? f->_Items.Data : f->_Items.end(), ImGuiTextFilter::ImGuiTextFilterItem(word_b, word_e)); + if (!is_excl) + f->_CountInclude++; } void ImGuiTextFilter::Build() { + // Parse filters _Items.resize(0); - ImGuiTextFilterItem input_range(InputBuf, InputBuf + ImStrlen(InputBuf)); - ImStrSplit(InputBuf, InputBuf + ImStrlen(InputBuf), ',', &_Items); - _CountInclude = 0; - for (ImGuiTextFilterItem& f : _Items) + const char* buf_e = InputBuf + ImStrlen(InputBuf); + const char* word_b = InputBuf; + const char* word_e = word_b; + while (word_e < buf_e) { - while (f.Begin < f.End && ImCharIsBlankA(f.Begin[0])) - f.Begin++; - while (f.End > f.Begin && ImCharIsBlankA(f.End[-1])) - f.End--; - if (f.Begin == f.End) - continue; - if (f.Begin[0] != '-') - _CountInclude += 1; + if (*word_e == ',') + { + ImGuiTextFilter_BuildAddItem(this, word_b, word_e); + word_b = word_e + 1; + } + word_e++; } + ImGuiTextFilter_BuildAddItem(this, word_b, word_e); } bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const { if (_Items.Size == 0) return true; - if (text == NULL) text = text_end = ""; - for (const ImGuiTextFilterItem& f : _Items) + // Filters are sorted so that '-' ones are always leading. + for (const ImGuiTextFilterItem& item : _Items) { - if (f.Begin == f.End) - continue; - if (f.Begin[0] == '-') + if (item.Begin[0] == '-') { - // Subtract - if (ImStristr(text, text_end, f.Begin + 1, f.End) != NULL) + if (ImStristr(text, text_end, item.Begin + 1, item.End) != NULL) // Exclude return false; } else { - // Grep - if (ImStristr(text, text_end, f.Begin, f.End) != NULL) + if (ImStristr(text, text_end, item.Begin, item.End) != NULL) // Include return true; } } - // Implicit * grep + // When no inclusion are specified (only exclusions) we implicitly pass if (_CountInclude == 0) return true; - return false; } diff --git a/imgui.h b/imgui.h index 786afe386..d66f70d24 100644 --- a/imgui.h +++ b/imgui.h @@ -2812,7 +2812,7 @@ struct ImGuiTextFilter // [Internal] Members char InputBuf[256]; // User input buffer int _CountInclude; // >= 0 - ImVector _Items; // Pre-parsed, trimmed items + ImVector _Items; // Pre-parsed, trimmed, reordered items }; // Helper: Growable text buffer for logging/accumulating text diff --git a/imgui_internal.h b/imgui_internal.h index 4a3fdca18..8b6ffb796 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -407,7 +407,7 @@ IMGUI_API const char* ImStrSkipBlank(const char* str); IMGUI_API int ImStrlenW(const ImWchar* str); // Computer string length (ImWchar string) IMGUI_API const char* ImStrbol(const char* buf_mid_line, const char* buf_begin); // Find beginning-of-line IM_MSVC_RUNTIME_CHECKS_OFF -inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; } +inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c & ~32 : c; } inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; } inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; } inline bool ImCharIsXdigitA(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); }