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);
enum class TreeStyle {
enum class TreeStyle : u8 {
Default = 0,
AutoExpanded = 1,
Flattened = 2
@ -82,18 +82,19 @@ namespace hex::ui {
void closeTreeNode(bool inlined) 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();
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);
std::string getDisplayName(const pl::ptrn::Pattern& pattern) const;
[[nodiscard]] std::string getDisplayName(const pl::ptrn::Pattern& pattern) const;
struct Filter {
std::vector<std::string> path;
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:
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
@ -113,11 +114,13 @@ namespace hex::ui {
std::string m_filterText;
Filter m_filter;
std::vector<pl::ptrn::Pattern*> m_filteredPatterns;
std::vector<std::string> m_currPatternPath;
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;
bool m_showFavoriteStars = false;
bool m_favoritesUpdated = false;
bool m_filtersUpdated = false;
bool m_showSpecName = false;
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;
if (filter.empty()) {
@ -192,6 +192,17 @@ namespace hex::ui {
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 {
return m_editingPattern == &pattern && m_editingPatternOffset == pattern.getOffset();
}
@ -201,18 +212,28 @@ namespace hex::ui {
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 (patternPath.size() != filterPath.size())
return false;
}
if (patternPath.size() <= filterPath.size()) {
for (ssize_t i = patternPath.size() - 1; i >= 0; i--) {
const auto &filter = filterPath[i];
if (filterPath.size() > patternPath.size())
return false;
if (patternPath[i] != filter && !filter.empty() && filter != "*") {
return false;
auto commonSize = std::min(filterPath.size(), patternPath.size());
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());
ON_SCOPE_EXIT { m_currPatternPath.pop_back(); };
if (matchesFilter(m_filter.path, m_currPatternPath, false)) {
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);
}
}
pattern.accept(*this);
}
void PatternDrawer::drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::IIterable &iterable, bool isInlined) {
@ -1128,9 +1135,10 @@ namespace hex::ui {
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)) {
m_filter = parseRValueFilter(m_filterText).value_or(Filter{ });
updateFilter();
}
ImGui::PopItemWidth();
@ -1172,7 +1180,7 @@ namespace hex::ui {
const auto &extension = formatter->getFileExtension();
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);
wolv::io::File output(path, wolv::io::File::Mode::Create);
@ -1183,10 +1191,10 @@ namespace hex::ui {
ImGui::EndPopup();
}
if (!m_favoritesUpdated) {
m_favoritesUpdated = true;
if (!m_filtersUpdated && !patterns.empty()) {
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) {
size_t updatedFavorites = 0;
@ -1217,7 +1225,7 @@ namespace hex::ui {
task.interrupt();
task.update();
if (this->matchesFilter(patternPath, path, true)) {
if (matchesFilter(patternPath, path, true)) {
favoritePattern = currPattern.clone();
updatedFavorites += 1;
@ -1235,6 +1243,8 @@ namespace hex::ui {
});
}
updateFilter();
}
if (beginPatternTable(patterns, m_sortedPatterns, height)) {
@ -1299,7 +1309,7 @@ namespace hex::ui {
m_showFavoriteStars = true;
for (auto &pattern : m_sortedPatterns) {
for (auto &pattern : m_filter.path.empty() ? m_sortedPatterns : m_filteredPatterns) {
ImGui::PushID(id);
this->draw(*pattern);
ImGui::PopID();
@ -1326,6 +1336,7 @@ namespace hex::ui {
m_visualizedPatterns.clear();
m_currVisualizedPattern = nullptr;
m_sortedPatterns.clear();
m_filteredPatterns.clear();
m_lastVisualizerError.clear();
m_currPatternPath.clear();
@ -1340,6 +1351,6 @@ namespace hex::ui {
m_groups.clear();
m_favoritesUpdated = false;
m_filtersUpdated = false;
}
}