1
0
mirror of synced 2024-12-01 02:37:18 +01:00

impr: Make pattern data filter behave more intuitively

This commit is contained in:
WerWolv 2024-05-15 18:25:08 +02:00
parent ceeda6de3b
commit 6a9e07729f
3 changed files with 51 additions and 37 deletions

@ -1 +1 @@
Subproject commit 0947102c05757c28c94553d40945ced478355f01 Subproject commit 7e43939feac350489d59d97e9d09bf61d463f6fe

View File

@ -24,7 +24,7 @@ namespace hex::ui {
void draw(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, const pl::PatternLanguage *runtime = nullptr, float height = 0.0F); void draw(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, const pl::PatternLanguage *runtime = nullptr, float height = 0.0F);
enum class TreeStyle { enum class TreeStyle : u8 {
Default = 0, Default = 0,
AutoExpanded = 1, AutoExpanded = 1,
Flattened = 2 Flattened = 2
@ -82,18 +82,19 @@ namespace hex::ui {
void closeTreeNode(bool inlined) const; void closeTreeNode(bool inlined) const;
bool sortPatterns(const ImGuiTableSortSpecs* sortSpecs, const pl::ptrn::Pattern * left, const pl::ptrn::Pattern * right) const; bool sortPatterns(const ImGuiTableSortSpecs* sortSpecs, const pl::ptrn::Pattern * left, const pl::ptrn::Pattern * right) const;
bool isEditingPattern(const pl::ptrn::Pattern& pattern) const; [[nodiscard]] bool isEditingPattern(const pl::ptrn::Pattern& pattern) const;
void resetEditing(); void resetEditing();
bool matchesFilter(const std::vector<std::string> &filterPath, const std::vector<std::string> &patternPath, bool fullMatch) const;
void traversePatternTree(pl::ptrn::Pattern &pattern, std::vector<std::string> &patternPath, const std::function<void(pl::ptrn::Pattern&)> &callback); void traversePatternTree(pl::ptrn::Pattern &pattern, std::vector<std::string> &patternPath, const std::function<void(pl::ptrn::Pattern&)> &callback);
std::string getDisplayName(const pl::ptrn::Pattern& pattern) const; [[nodiscard]] std::string getDisplayName(const pl::ptrn::Pattern& pattern) const;
struct Filter { struct Filter {
std::vector<std::string> path; std::vector<std::string> path;
std::optional<pl::core::Token::Literal> value; std::optional<pl::core::Token::Literal> value;
}; };
std::optional<Filter> parseRValueFilter(const std::string &filter) const; [[nodiscard]] static bool matchesFilter(const std::vector<std::string> &filterPath, const std::vector<std::string> &patternPath, bool fullMatch);
[[nodiscard]] static std::optional<Filter> parseRValueFilter(const std::string &filter);
void updateFilter();
private: private:
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd; std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
@ -113,11 +114,13 @@ namespace hex::ui {
std::string m_filterText; std::string m_filterText;
Filter m_filter; Filter m_filter;
std::vector<pl::ptrn::Pattern*> m_filteredPatterns;
std::vector<std::string> m_currPatternPath; std::vector<std::string> m_currPatternPath;
std::map<std::vector<std::string>, std::unique_ptr<pl::ptrn::Pattern>> m_favorites; std::map<std::vector<std::string>, std::unique_ptr<pl::ptrn::Pattern>> m_favorites;
std::map<std::string, std::vector<std::unique_ptr<pl::ptrn::Pattern>>> m_groups; std::map<std::string, std::vector<std::unique_ptr<pl::ptrn::Pattern>>> m_groups;
bool m_showFavoriteStars = false; bool m_showFavoriteStars = false;
bool m_favoritesUpdated = false; bool m_filtersUpdated = false;
bool m_showSpecName = false; bool m_showSpecName = false;
TaskHolder m_favoritesUpdateTask; TaskHolder m_favoritesUpdateTask;

View File

@ -151,7 +151,7 @@ namespace hex::ui {
} }
std::optional<PatternDrawer::Filter> PatternDrawer::parseRValueFilter(const std::string &filter) const { std::optional<PatternDrawer::Filter> PatternDrawer::parseRValueFilter(const std::string &filter) {
Filter result; Filter result;
if (filter.empty()) { if (filter.empty()) {
@ -192,6 +192,17 @@ namespace hex::ui {
return result; return result;
} }
void PatternDrawer::updateFilter() {
m_filteredPatterns.clear();
std::vector<std::string> treePath;
for (auto &pattern : m_sortedPatterns) {
traversePatternTree(*pattern, treePath, [this, &treePath](auto &pattern){
if (matchesFilter(m_filter.path, treePath, false))
m_filteredPatterns.push_back(&pattern);
});
}
}
bool PatternDrawer::isEditingPattern(const pl::ptrn::Pattern& pattern) const { bool PatternDrawer::isEditingPattern(const pl::ptrn::Pattern& pattern) const {
return m_editingPattern == &pattern && m_editingPatternOffset == pattern.getOffset(); return m_editingPattern == &pattern && m_editingPatternOffset == pattern.getOffset();
} }
@ -201,18 +212,28 @@ namespace hex::ui {
m_editingPatternOffset = 0x00; m_editingPatternOffset = 0x00;
} }
bool PatternDrawer::matchesFilter(const std::vector<std::string> &filterPath, const std::vector<std::string> &patternPath, bool fullMatch) const { bool PatternDrawer::matchesFilter(const std::vector<std::string> &filterPath, const std::vector<std::string> &patternPath, bool fullMatch) {
if (fullMatch) { if (fullMatch) {
if (patternPath.size() != filterPath.size()) if (patternPath.size() != filterPath.size())
return false; return false;
} }
if (patternPath.size() <= filterPath.size()) { if (filterPath.size() > patternPath.size())
for (ssize_t i = patternPath.size() - 1; i >= 0; i--) { return false;
const auto &filter = filterPath[i];
if (patternPath[i] != filter && !filter.empty() && filter != "*") { auto commonSize = std::min(filterPath.size(), patternPath.size());
return false; for (size_t i = patternPath.size() - commonSize; i < patternPath.size(); i += 1) {
const auto &filter = filterPath[i - (patternPath.size() - commonSize)];
if (filter.empty())
return false;
if (filter != "*") {
if (i == (patternPath.size() - 1)) {
if (!patternPath[i].starts_with(filter))
return false;
} else {
if (patternPath[i] != filter)
return false;
} }
} }
} }
@ -887,21 +908,7 @@ namespace hex::ui {
m_currPatternPath.push_back(pattern.getVariableName()); m_currPatternPath.push_back(pattern.getVariableName());
ON_SCOPE_EXIT { m_currPatternPath.pop_back(); }; ON_SCOPE_EXIT { m_currPatternPath.pop_back(); };
if (matchesFilter(m_filter.path, m_currPatternPath, false)) { pattern.accept(*this);
if (m_filter.value.has_value()) {
auto patternValue = pattern.getValue();
if (patternValue == m_filter.value) {
pattern.accept(*this);
} else if (!matchesFilter(m_filter.path, m_currPatternPath, true)) {
pattern.accept(*this);
} else if (patternValue.isPattern() && m_filter.value->isString()) {
if (patternValue.toString(true) == m_filter.value->toString(false))
pattern.accept(*this);
}
} else {
pattern.accept(*this);
}
}
} }
void PatternDrawer::drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::IIterable &iterable, bool isInlined) { void PatternDrawer::drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::IIterable &iterable, bool isInlined) {
@ -1128,9 +1135,10 @@ namespace hex::ui {
this->resetEditing(); this->resetEditing();
} }
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetTextLineHeightWithSpacing() * 9.5); ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetTextLineHeightWithSpacing() * 8.5F);
if (ImGuiExt::InputTextIcon("##Search", ICON_VS_FILTER, m_filterText)) { if (ImGuiExt::InputTextIcon("##Search", ICON_VS_FILTER, m_filterText)) {
m_filter = parseRValueFilter(m_filterText).value_or(Filter{ }); m_filter = parseRValueFilter(m_filterText).value_or(Filter{ });
updateFilter();
} }
ImGui::PopItemWidth(); ImGui::PopItemWidth();
@ -1172,7 +1180,7 @@ namespace hex::ui {
const auto &extension = formatter->getFileExtension(); const auto &extension = formatter->getFileExtension();
if (ImGui::MenuItem(name.c_str())) { if (ImGui::MenuItem(name.c_str())) {
fs::openFileBrowser(fs::DialogMode::Save, { { name.c_str(), extension.c_str() } }, [&](const std::fs::path &path) { fs::openFileBrowser(fs::DialogMode::Save, { { name, extension } }, [&](const std::fs::path &path) {
auto result = formatter->format(*runtime); auto result = formatter->format(*runtime);
wolv::io::File output(path, wolv::io::File::Mode::Create); wolv::io::File output(path, wolv::io::File::Mode::Create);
@ -1183,10 +1191,10 @@ namespace hex::ui {
ImGui::EndPopup(); ImGui::EndPopup();
} }
if (!m_favoritesUpdated) { if (!m_filtersUpdated && !patterns.empty()) {
m_favoritesUpdated = true; m_filtersUpdated = true;
if (!patterns.empty() && !m_favoritesUpdateTask.isRunning()) { if (!m_favoritesUpdateTask.isRunning()) {
m_favoritesUpdateTask = TaskManager::createTask("hex.ui.pattern_drawer.updating"_lang, TaskManager::NoProgress, [this, patterns](auto &task) { m_favoritesUpdateTask = TaskManager::createTask("hex.ui.pattern_drawer.updating"_lang, TaskManager::NoProgress, [this, patterns](auto &task) {
size_t updatedFavorites = 0; size_t updatedFavorites = 0;
@ -1217,7 +1225,7 @@ namespace hex::ui {
task.interrupt(); task.interrupt();
task.update(); task.update();
if (this->matchesFilter(patternPath, path, true)) { if (matchesFilter(patternPath, path, true)) {
favoritePattern = currPattern.clone(); favoritePattern = currPattern.clone();
updatedFavorites += 1; updatedFavorites += 1;
@ -1235,6 +1243,8 @@ namespace hex::ui {
}); });
} }
updateFilter();
} }
if (beginPatternTable(patterns, m_sortedPatterns, height)) { if (beginPatternTable(patterns, m_sortedPatterns, height)) {
@ -1299,7 +1309,7 @@ namespace hex::ui {
m_showFavoriteStars = true; m_showFavoriteStars = true;
for (auto &pattern : m_sortedPatterns) { for (auto &pattern : m_filter.path.empty() ? m_sortedPatterns : m_filteredPatterns) {
ImGui::PushID(id); ImGui::PushID(id);
this->draw(*pattern); this->draw(*pattern);
ImGui::PopID(); ImGui::PopID();
@ -1326,6 +1336,7 @@ namespace hex::ui {
m_visualizedPatterns.clear(); m_visualizedPatterns.clear();
m_currVisualizedPattern = nullptr; m_currVisualizedPattern = nullptr;
m_sortedPatterns.clear(); m_sortedPatterns.clear();
m_filteredPatterns.clear();
m_lastVisualizerError.clear(); m_lastVisualizerError.clear();
m_currPatternPath.clear(); m_currPatternPath.clear();
@ -1340,6 +1351,6 @@ namespace hex::ui {
m_groups.clear(); m_groups.clear();
m_favoritesUpdated = false; m_filtersUpdated = false;
} }
} }