mirror of
https://github.com/ocornut/imgui.git
synced 2026-09-26 16:05:45 +03:00
ImGuiTextFilter: reworked filter to make space an AND operator. Demo: tweaked demo.
Removed FilterOp, MinWordSize added a few commits ago.
This commit is contained in:
parent
420f179341
commit
d5c68c301a
4 changed files with 73 additions and 48 deletions
|
|
@ -84,8 +84,10 @@ Other Changes:
|
||||||
hasn't been owned by another items. This is more correct and also necessary
|
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)
|
to avoid Drags/Sliders cancelling also triggering a cancel menu. (#8564, #9534)
|
||||||
- ImGuiTextFilter:
|
- ImGuiTextFilter:
|
||||||
- Added support for space ' ' as separator, which is more standard. (#2435, #30)
|
- Added support for space as an "and" filter, which is the standard. (#2435, #30)
|
||||||
- Added support for quoted "xxx" blocks to e.g. match words sequences. (#2435)
|
e.g. w/ filter 'hello world' (without quotes) both words needs to be in input data.
|
||||||
|
- Added support for double-quoted "xxx" blocks to e.g. match words sequences. (#2435)
|
||||||
|
e.g. w/ filter "hello world" the exact sequence needs to be in input data.
|
||||||
- Fixed filtering when mixing "include" and "-exclude" keyword so that an "-exclude"
|
- Fixed filtering when mixing "include" and "-exclude" keyword so that an "-exclude"
|
||||||
match always filters out. (#2435) [@kudaba, @ocornut]
|
match always filters out. (#2435) [@kudaba, @ocornut]
|
||||||
- Added `DrawWithHint()` function. (#6206, #6395, #6447)
|
- Added `DrawWithHint()` function. (#6206, #6395, #6447)
|
||||||
|
|
|
||||||
78
imgui.cpp
78
imgui.cpp
|
|
@ -3094,9 +3094,7 @@ IM_MSVC_RUNTIME_CHECKS_RESTORE
|
||||||
ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077
|
ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077
|
||||||
{
|
{
|
||||||
InputBuf[0] = 0;
|
InputBuf[0] = 0;
|
||||||
FilterOp = '|';
|
_CountExclude = 0;
|
||||||
MinWordSize = 1;
|
|
||||||
_CountExclude = _CountInclude = 0;
|
|
||||||
if (default_filter)
|
if (default_filter)
|
||||||
{
|
{
|
||||||
ImStrncpy(InputBuf, default_filter, IM_COUNTOF(InputBuf));
|
ImStrncpy(InputBuf, default_filter, IM_COUNTOF(InputBuf));
|
||||||
|
|
@ -3118,14 +3116,15 @@ bool ImGuiTextFilter::DrawWithHint(const char* label, const char* hint)
|
||||||
return value_changed;
|
return value_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse filter and split into items
|
// Parse filter and split into a format optimal for PassFilter()
|
||||||
void ImGuiTextFilter::Build()
|
void ImGuiTextFilter::Build()
|
||||||
{
|
{
|
||||||
_Items.resize(0);
|
_Items.resize(0);
|
||||||
_CountExclude = _CountInclude = 0;
|
_CountExclude = 0;
|
||||||
IM_ASSERT(FilterOp == '|' || FilterOp == '&');
|
|
||||||
const char* buf_e = InputBuf + ImStrlen(InputBuf);
|
const char* buf_e = InputBuf + ImStrlen(InputBuf);
|
||||||
const char* word_e;
|
const char* word_e;
|
||||||
|
int seq_incl_start_idx = -1;
|
||||||
for (const char* word_b = InputBuf; word_b < buf_e; word_b = word_e + 1)
|
for (const char* word_b = InputBuf; word_b < buf_e; word_b = word_e + 1)
|
||||||
{
|
{
|
||||||
// Trim blanks
|
// Trim blanks
|
||||||
|
|
@ -3151,20 +3150,33 @@ void ImGuiTextFilter::Build()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Min length
|
// Min length
|
||||||
if (word_e - word_b < MinWordSize)
|
if (word_e - word_b > 0)
|
||||||
continue;
|
{
|
||||||
|
// Add to list. The '-' is not stored in items but implicitly inferred using (n < CountExclude).
|
||||||
|
// FIXME-OPT: as items are derived from user input buffer and we expect the insert() to behave sanely.
|
||||||
|
if (is_excl)
|
||||||
|
{
|
||||||
|
_Items.insert(_Items.Data + _CountExclude, ImGuiTextFilter::ImGuiTextFilterItem(word_b, word_e));
|
||||||
|
_CountExclude++;
|
||||||
|
if (seq_incl_start_idx != -1)
|
||||||
|
seq_incl_start_idx++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (seq_incl_start_idx == -1)
|
||||||
|
seq_incl_start_idx = _Items.Size;
|
||||||
|
_Items.insert(_Items.Data + _Items.Size, ImGuiTextFilter::ImGuiTextFilterItem(word_b, word_e));
|
||||||
|
_Items.Data[seq_incl_start_idx].CountInclude++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add to list
|
// Next sequence
|
||||||
// The '-' is not stored in items but implicitly inferred using (n < CountExclude).
|
if (word_e[0] == ',')
|
||||||
// FIXME-OPT: about ~push_front(): as N is derived from user inputs we expect this to be fine.
|
seq_incl_start_idx = -1;
|
||||||
_Items.insert(is_excl ? _Items.Data : _Items.Data + _Items.Size, ImGuiTextFilter::ImGuiTextFilterItem(word_b, word_e));
|
|
||||||
if (is_excl)
|
|
||||||
_CountExclude++;
|
|
||||||
else
|
|
||||||
_CountInclude++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Could use a specialized ImStristr() + pre-convert our filter to uppercase.
|
||||||
bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
|
bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
|
||||||
{
|
{
|
||||||
if (_Items.Size == 0)
|
if (_Items.Size == 0)
|
||||||
|
|
@ -3173,24 +3185,28 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
|
||||||
text = text_end = "";
|
text = text_end = "";
|
||||||
|
|
||||||
// Filters are sorted so that '-' ones are always leading.
|
// Filters are sorted so that '-' ones are always leading.
|
||||||
int n;
|
ImGuiTextFilterItem* seq = _Items.Data;
|
||||||
for (n = 0; n < _CountExclude; n++)
|
ImGuiTextFilterItem* seq_excl_end = _Items.Data + _CountExclude;
|
||||||
if (ImStristr(text, text_end, _Items.Data[n].Begin, _Items.Data[n].End) != NULL)
|
for (; seq < seq_excl_end; seq++)
|
||||||
|
if (ImStristr(text, text_end, seq->Begin, seq->Begin + seq->Len) != NULL)
|
||||||
return false;
|
return false;
|
||||||
const bool is_and_filter = (FilterOp == '&');
|
|
||||||
for (; n < _Items.Size; n++)
|
|
||||||
{
|
|
||||||
const bool is_match = ImStristr(text, text_end, _Items.Data[n].Begin, _Items.Data[n].End) != NULL;
|
|
||||||
if (is_match && !is_and_filter) // or incl 1 -> true
|
|
||||||
return true; // or incl 0 -> continue
|
|
||||||
if (!is_match && is_and_filter) // and incl 1 -> continue
|
|
||||||
return false; // and incl 0 -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
// When no inclusion are specified (only exclusions) we implicitly pass
|
// Process includes
|
||||||
if (_CountInclude == 0)
|
ImGuiTextFilterItem* seq_incl_end = _Items.Data + _Items.Size;
|
||||||
|
if (seq == seq_incl_end) // When no inclusion are specified (only exclusions) we implicitly pass
|
||||||
return true;
|
return true;
|
||||||
return is_and_filter;
|
while (seq < seq_incl_end)
|
||||||
|
{
|
||||||
|
ImGuiTextFilterItem* seq_next = seq + seq->CountInclude;
|
||||||
|
IM_ASSERT_PARANOID(seq->CountInclude > 0 && seq_next <= seq_incl_end);
|
||||||
|
for (; seq < seq_next; seq++)
|
||||||
|
if (ImStristr(text, text_end, seq->Begin, seq->Begin + seq->Len) == NULL)
|
||||||
|
break;
|
||||||
|
if (seq == seq_next) // All matched
|
||||||
|
return true;
|
||||||
|
seq = seq_next; // Try next
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
|
||||||
14
imgui.h
14
imgui.h
|
|
@ -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; }
|
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 e.g. 'aaa bbb -ccc'.
|
// Helper: Parse and apply text filters e.g. 'aaa bbb' (all), 'aaa,bbb' (any), '-aaa' (exclude), '"Hello, world"' (exact sequence)
|
||||||
struct ImGuiTextFilter
|
struct ImGuiTextFilter
|
||||||
{
|
{
|
||||||
IMGUI_API ImGuiTextFilter(const char* default_filter = "");
|
IMGUI_API ImGuiTextFilter(const char* default_filter = "");
|
||||||
|
|
@ -2801,20 +2801,18 @@ struct ImGuiTextFilter
|
||||||
inline bool Draw(const char* label, float width) { if (width != 0.0f) ImGui::SetNextItemWidth(width); return Draw(label); }
|
inline bool Draw(const char* label, float width) { if (width != 0.0f) ImGui::SetNextItemWidth(width); return Draw(label); }
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// [Internal] Don't use! Will be replaced with ImStrv.
|
// [Internal] Types
|
||||||
struct ImGuiTextFilterItem
|
struct ImGuiTextFilterItem
|
||||||
{
|
{
|
||||||
const char* Begin;
|
const char* Begin;
|
||||||
const char* End;
|
int Len;
|
||||||
ImGuiTextFilterItem(const char* b, const char* e) { Begin = b; End = e; }
|
int CountInclude; // >0 when beginning of an AND chain.
|
||||||
|
ImGuiTextFilterItem(const char* b, const char* e) { IM_ASSERT(e > b); Begin = b; Len = (int)(e - b); CountInclude = 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// [Internal] Members
|
// [Internal] Members
|
||||||
char InputBuf[256]; // User input buffer
|
char InputBuf[256]; // User input buffer
|
||||||
char FilterOp; // == '|' (any) pr '&' (all)
|
int _CountExclude; // >= 0 count of leading exclude
|
||||||
ImU8 MinWordSize; // == 1
|
|
||||||
int _CountExclude; // >= 0
|
|
||||||
int _CountInclude; // >= 0
|
|
||||||
ImVector<ImGuiTextFilterItem> _Items; // Pre-parsed, trimmed, reordered items
|
ImVector<ImGuiTextFilterItem> _Items; // Pre-parsed, trimmed, reordered items
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3943,15 +3943,24 @@ static void DemoWindowWidgetsTextFilter()
|
||||||
static ImGuiTextFilter filter;
|
static ImGuiTextFilter filter;
|
||||||
ImGui::Text("Filter usage:\n"
|
ImGui::Text("Filter usage:\n"
|
||||||
" \"\" display all lines\n"
|
" \"\" display all lines\n"
|
||||||
" \"xxx\" display lines containing \"xxx\"\n"
|
" xxx display lines containing \"xxx\"\n"
|
||||||
" \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
|
" xxx yyy display lines containing \"xxx\" and \"yyy\"\n"
|
||||||
" \"-xxx\" hide lines containing \"xxx\"");
|
" \"xxx yyy\" display lines containing \"xxx yyy\"\n"
|
||||||
|
" xxx,yyy display lines containing \"xxx\" or \"yyy\"\n"
|
||||||
|
" -xxx hide lines containing \"xxx\"");
|
||||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
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" };
|
if (ImGui::BeginChild("##items", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 15), ImGuiChildFlags_FrameStyle))
|
||||||
for (int i = 0; i < IM_COUNTOF(lines); i++)
|
{
|
||||||
if (filter.PassFilter(lines[i]))
|
const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
|
||||||
ImGui::BulletText("%s", lines[i]);
|
for (const char* item : lines)
|
||||||
|
if (filter.PassFilter(item))
|
||||||
|
ImGui::TextUnformatted(item);
|
||||||
|
for (const char* item : ExampleNames)
|
||||||
|
if (filter.PassFilter(item))
|
||||||
|
ImGui::TextUnformatted(item);
|
||||||
|
}
|
||||||
|
ImGui::EndChild();
|
||||||
ImGui::TreePop();
|
ImGui::TreePop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue