impr: Make pattern data filter behave more intuitively
This commit is contained in:
parent
ceeda6de3b
commit
6a9e07729f
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 0947102c05757c28c94553d40945ced478355f01
|
Subproject commit 7e43939feac350489d59d97e9d09bf61d463f6fe
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user