ImGuiTextFilter: Added support for space ' ' as separator. Added support for quoted "xxx" blocks. (#2435, #30)

This commit is contained in:
ocornut 2026-09-18 19:20:42 +02:00
parent 54f86be71e
commit c74e7e93a3
4 changed files with 49 additions and 37 deletions

View file

@ -84,10 +84,12 @@ 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:
- Added support for space ' ' as separator, which is more standard. (#2435, #30)
- Added support for quoted "xxx" blocks to e.g. match words sequences. (#2435)
- 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)
- Added a "incl -excl" hint by default when the search field is empty. (#6206, #6395, #6447)
- Style:
- Inverted `ImGuiCol_TitleBgXXX` colors for `StyleColorsLight()` so that the selected
window title bar appears brighter.

View file

@ -3090,7 +3090,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE
// [SECTION] ImGuiTextFilter
//-----------------------------------------------------------------------------
// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
// Helper: Parse and apply text filters e.g. 'aaa bbb -ccc'.
ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077
{
InputBuf[0] = 0;
@ -3104,7 +3104,7 @@ ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077
bool ImGuiTextFilter::Draw(const char* label)
{
return DrawWithHint(label, "incl,-excl");
return DrawWithHint(label, "incl -excl");
}
// Use ImGui::SetNextItemWidth() manually if you want to use this.
@ -3118,17 +3118,20 @@ bool ImGuiTextFilter::DrawWithHint(const char* label, const char* hint)
static void ImGuiTextFilter_BuildAddItem(ImGuiTextFilter* f, const char* word_b, const char* word_e)
{
// 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)
// Trim blanks
if (word_b < word_e && word_b[0] != '\"')
{
while (word_b < word_e && ImCharIsBlankA(word_b[0])) // FIXME: UTF-8 support
word_b++;
while (word_e > word_b && ImCharIsBlankA(word_e[-1]))
word_e--;
}
const bool is_excl = (word_b < word_e && word_b[0] == '-');
if (word_e - word_b - (is_excl ? 1 : 0) <= 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] == '-');
// FIXME-OPT: about ~push_front(): as N is derived from user inputs we expect this to be fine.
f->_Items.insert(is_excl ? f->_Items.Data : f->_Items.end(), ImGuiTextFilter::ImGuiTextFilterItem(word_b, word_e));
if (!is_excl)
f->_CountInclude++;
@ -3140,18 +3143,26 @@ void ImGuiTextFilter::Build()
_Items.resize(0);
_CountInclude = 0;
const char* buf_e = InputBuf + ImStrlen(InputBuf);
const char* word_b = InputBuf;
const char* word_e = word_b;
while (word_e < buf_e)
const char* word_e;
for (const char* word_b = InputBuf; word_b < buf_e; word_b = word_e + 1)
{
if (*word_e == ',')
const bool is_excl = (word_b[0] == '-');
if (word_b[0] == '\"' || (is_excl && word_b + 1 < buf_e && word_b[1] == '\"'))
{
ImGuiTextFilter_BuildAddItem(this, word_b, word_e);
word_b = word_e + 1;
// Parsing "word". Store leading " to distinguish -"word" from "-word", but omit trailing ".
word_e = ImStrchrRange(word_b + (is_excl ? 2 : 1), buf_e, '\"');
if (word_e == NULL)
word_e = buf_e;
}
word_e++;
else
{
// Handle both ' ' and ',' separators.
for (word_e = word_b; word_e < buf_e; word_e++)
if (*word_e == ' ' || *word_e == ',')
break;
}
ImGuiTextFilter_BuildAddItem(this, word_b, word_e);
}
ImGuiTextFilter_BuildAddItem(this, word_b, word_e);
}
bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
@ -3164,16 +3175,15 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
// Filters are sorted so that '-' ones are always leading.
for (const ImGuiTextFilterItem& item : _Items)
{
if (item.Begin[0] == '-')
{
if (ImStristr(text, text_end, item.Begin + 1, item.End) != NULL) // Exclude
return false;
}
else
{
if (ImStristr(text, text_end, item.Begin, item.End) != NULL) // Include
return true;
}
const char* word_b = item.Begin;
const char* word_e = item.End;
const bool is_excl = (word_b[0] == '-');
if (is_excl)
word_b++;
if (word_b < word_e && word_b[0] == '\"')
word_b++;
if (ImStristr(text, text_end, word_b, word_e) != NULL)
return is_excl ? false : true;
}
// When no inclusion are specified (only exclusions) we implicitly pass

View file

@ -2785,7 +2785,7 @@ struct ImGuiOnceUponAFrame
operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; }
};
// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
// Helper: Parse and apply text filters e.g. 'aaa bbb -ccc'.
struct ImGuiTextFilter
{
IMGUI_API ImGuiTextFilter(const char* default_filter = "");
@ -2796,7 +2796,7 @@ struct ImGuiTextFilter
// Helper to call InputText() + Build() when buffer is changed.
IMGUI_API bool Draw(const char* label = "Filter");
IMGUI_API bool DrawWithHint(const char* label = "Filter", const char* hint = "incl,-excl");
IMGUI_API bool DrawWithHint(const char* label = "Filter", const char* hint = "incl -excl");
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
inline bool Draw(const char* label, float width) { if (width != 0.0f) ImGui::SetNextItemWidth(width); return Draw(label); }
#endif

View file

@ -1453,7 +1453,7 @@ static void DemoWindowWidgetsComboBoxes()
}
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F);
ImGui::SetNextItemWidth(-FLT_MIN);
filter.DrawWithHint("##Filter", "Filter (incl,-excl)");
filter.DrawWithHint("##Filter", "Filter (incl -excl)");
for (int n = 0; n < IM_COUNTOF(items); n++)
{
@ -3947,7 +3947,7 @@ static void DemoWindowWidgetsTextFilter()
" \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
" \"-xxx\" hide lines containing \"xxx\"");
ImGui::SetNextItemWidth(-FLT_MIN);
filter.DrawWithHint("##Filter", "Filter (incl,-excl)");
filter.DrawWithHint("##Filter", "Filter (incl -excl)");
const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
for (int i = 0; i < IM_COUNTOF(lines); i++)
if (filter.PassFilter(lines[i]))
@ -8833,7 +8833,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
static ImGuiTextFilter filter;
SetNextItemWidth(-FLT_MIN);
filter.DrawWithHint("##FilterColors", "Filter Colors (incl,-excl)");
filter.DrawWithHint("##FilterColors", "Filter Colors (incl -excl)");
SetNextWindowSizeConstraints(ImVec2(0.0f, GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX));
BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
@ -9250,7 +9250,7 @@ struct ExampleAppConsole
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
ImGui::SetNextItemWidth(-FLT_MIN);
Filter.DrawWithHint("##Filter", "Filter (incl,-excl)");
Filter.DrawWithHint("##Filter", "Filter (incl -excl)");
ImGui::Separator();
// Reserve enough left-over height for 1 separator + 1 input text
@ -9586,7 +9586,7 @@ struct ExampleAppLog
bool copy = ImGui::Button("Copy");
ImGui::SameLine();
ImGui::SetNextItemWidth(-FLT_MIN);
Filter.DrawWithHint("##Filter", "Filter (incl,-excl)");
Filter.DrawWithHint("##Filter", "Filter (incl -excl)");
ImGui::Separator();
@ -9781,7 +9781,7 @@ struct ExampleAppPropertyEditor
ImGui::Text("(%d root nodes)", root_node->Childs.Size);
ImGui::SetNextItemWidth(-FLT_MIN);
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_COUNTOF(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
if (ImGui::InputTextWithHint("##Filter", "incl -excl", Filter.InputBuf, IM_COUNTOF(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
Filter.Build();
ImGui::PopItemFlag();