UI: support different main word heuristics in string search

Currently, we always prioritize the words in the last section of a search item
(the words that are highlighted). This generally works well, but the situation
is a bit different for link-drag-search, because there the last part is the socket
name, which is usually less descriptive than the node name.

This patch allows us to use different heuristics to select the prioritized section
per search.

Unfortunately, the link-drag-search is not fully consistent with itself. Sometimes
the last group is a socket name, but sometimes it's also the mode of a node
(`Math > Add`). Therefore, the patch currently simply prioritizes all words in the
same instead of prioritizing only the first part. This seems to work much better
than before even if not perfect in all cases yet.

Pull Request: https://projects.blender.org/blender/blender/pulls/113648
This commit is contained in:
Jacques Lucke
2023-10-20 13:50:10 +02:00
parent 57a5c6c4be
commit 09e6ebb5f0
5 changed files with 42 additions and 6 deletions

View File

@@ -44,6 +44,17 @@ struct RecentCache {
Map<std::string, int> logical_time_by_str;
};
/**
* Sometimes every search item has multiple parts. For example, when using menu search, each nested
* menu is a separate part. Usually, one of those parts is highlighted in the UI and should be
* prioritized in the search.
*/
enum class MainWordsHeuristic {
FirstGroup,
LastGroup,
All,
};
/**
* Non templated base class so that its methods can be implemented outside of this header.
*/
@@ -52,6 +63,7 @@ class StringSearchBase {
LinearAllocator<> allocator_;
Vector<SearchItem> items_;
const RecentCache *recent_cache_ = nullptr;
MainWordsHeuristic main_words_heuristic_;
protected:
void add_impl(StringRef str, void *user_data, int weight);
@@ -70,9 +82,10 @@ class StringSearchBase {
*/
template<typename T> class StringSearch : private StringSearchBase {
public:
StringSearch(const RecentCache *recent_cache = nullptr)
StringSearch(const RecentCache *recent_cache, const MainWordsHeuristic main_words_heuristic)
{
this->recent_cache_ = recent_cache;
recent_cache_ = recent_cache;
main_words_heuristic_ = main_words_heuristic;
}
/**

View File

@@ -487,7 +487,24 @@ void StringSearchBase::add_impl(const StringRef str, void *user_data, const int
const int recent_time = recent_cache_ ?
recent_cache_->logical_time_by_str.lookup_default(str, -1) :
-1;
const int main_group_id = word_group_ids.is_empty() ? 0 : word_group_ids.last();
int main_group_id = 0;
if (!word_group_ids.is_empty()) {
switch (main_words_heuristic_) {
case MainWordsHeuristic::FirstGroup: {
main_group_id = 0;
break;
}
case MainWordsHeuristic::LastGroup: {
main_group_id = word_group_ids.last();
break;
}
case MainWordsHeuristic::All: {
main_group_id = 0;
word_group_ids.fill(0);
break;
}
}
}
int main_group_length = 0;
for (const int i : words.index_range()) {

View File

@@ -28,7 +28,11 @@ void read_recent_searches_file();
*/
template<typename T> class StringSearch : public blender::string_search::StringSearch<T> {
public:
StringSearch() : blender::string_search::StringSearch<T>(get_recent_cache_or_null()) {}
StringSearch(const blender::string_search::MainWordsHeuristic main_word_heuristic =
blender::string_search::MainWordsHeuristic::LastGroup)
: blender::string_search::StringSearch<T>(get_recent_cache_or_null(), main_word_heuristic)
{
}
};
} // namespace blender::ui::string_search

View File

@@ -453,7 +453,8 @@ static void id_search_cb_tagged(const bContext *C,
ListBase *lb = template_ui->idlb;
const int flag = RNA_property_flag(template_ui->prop);
blender::string_search::StringSearch<ID> search;
blender::string_search::StringSearch<ID> search{nullptr,
blender::string_search::MainWordsHeuristic::All};
/* ID listbase */
LISTBASE_FOREACH (ID *, id, lb) {

View File

@@ -361,7 +361,8 @@ static void link_drag_search_update_fn(
storage.update_items_tag = false;
}
ui::string_search::StringSearch<SocketLinkOperation> search;
ui::string_search::StringSearch<SocketLinkOperation> search{
string_search::MainWordsHeuristic::All};
for (SocketLinkOperation &op : storage.search_link_ops) {
search.add(op.name, &op, op.weight);