1
0
mirror of synced 2024-12-14 08:42:54 +01:00
ImHex/plugins/builtin/include/ui/pattern_drawer.hpp

121 lines
5.2 KiB
C++
Raw Normal View History

#pragma once
#include <hex/api/task_manager.hpp>
#include <hex/api/content_registry.hpp>
#include <pl/patterns/pattern.hpp>
#include <pl/pattern_visitor.hpp>
#include <pl/formatters.hpp>
#include <set>
2023-07-23 09:14:00 +02:00
struct ImGuiTableSortSpecs;
namespace hex::plugin::builtin::ui {
class PatternDrawer : public pl::PatternVisitor {
public:
PatternDrawer() {
this->m_formatters = pl::gen::fmt::createFormatters();
}
virtual ~PatternDrawer() = default;
2023-11-10 20:47:08 +01:00
void draw(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, const pl::PatternLanguage *runtime = nullptr, float height = 0.0F);
enum class TreeStyle {
Default = 0,
AutoExpanded = 1,
Flattened = 2
};
void setTreeStyle(TreeStyle style) { this->m_treeStyle = style; }
void setSelectionCallback(std::function<void(Region)> callback) { this->m_selectionCallback = std::move(callback); }
void enableRowColoring(bool enabled) { this->m_rowColoring = enabled; }
void reset();
private:
void draw(pl::ptrn::Pattern& pattern);
public:
void visit(pl::ptrn::PatternArrayDynamic& pattern) override;
void visit(pl::ptrn::PatternArrayStatic& pattern) override;
void visit(pl::ptrn::PatternBitfieldField& pattern) override;
void visit(pl::ptrn::PatternBitfieldArray& pattern) override;
void visit(pl::ptrn::PatternBitfield& pattern) override;
void visit(pl::ptrn::PatternBoolean& pattern) override;
void visit(pl::ptrn::PatternCharacter& pattern) override;
void visit(pl::ptrn::PatternEnum& pattern) override;
void visit(pl::ptrn::PatternFloat& pattern) override;
void visit(pl::ptrn::PatternPadding& pattern) override;
void visit(pl::ptrn::PatternPointer& pattern) override;
void visit(pl::ptrn::PatternSigned& pattern) override;
void visit(pl::ptrn::PatternString& pattern) override;
void visit(pl::ptrn::PatternStruct& pattern) override;
void visit(pl::ptrn::PatternUnion& pattern) override;
void visit(pl::ptrn::PatternUnsigned& pattern) override;
void visit(pl::ptrn::PatternWideCharacter& pattern) override;
void visit(pl::ptrn::PatternWideString& pattern) override;
private:
constexpr static auto ChunkSize = 512;
constexpr static auto DisplayEndStep = 64;
void drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::IIterable &iterable, bool isInlined);
u64& getDisplayEnd(const pl::ptrn::Pattern& pattern);
void makeSelectable(const pl::ptrn::Pattern &pattern);
void drawValueColumn(pl::ptrn::Pattern& pattern);
void drawVisualizer(const std::map<std::string, ContentRegistry::PatternLanguage::impl::Visualizer> &visualizers, const std::vector<pl::core::Token::Literal> &arguments, pl::ptrn::Pattern &pattern, pl::ptrn::IIterable &iterable, bool reset);
void drawFavoriteColumn(const pl::ptrn::Pattern& pattern);
2023-11-10 20:47:08 +01:00
bool beginPatternTable(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, std::vector<pl::ptrn::Pattern*> &sortedPatterns, float height) const;
bool createTreeNode(const pl::ptrn::Pattern& pattern, bool leaf = false);
2023-11-10 20:47:08 +01:00
void createDefaultEntry(const pl::ptrn::Pattern &pattern);
void closeTreeNode(bool inlined) const;
2023-07-23 09:14:00 +02:00
bool sortPatterns(const ImGuiTableSortSpecs* sortSpecs, const pl::ptrn::Pattern * left, const pl::ptrn::Pattern * right) const;
bool isEditingPattern(const pl::ptrn::Pattern& pattern) const;
void resetEditing();
2023-11-10 20:47:08 +01:00
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);
2023-07-23 09:14:00 +02:00
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;
private:
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
std::vector<pl::ptrn::Pattern*> m_sortedPatterns;
const pl::ptrn::Pattern *m_editingPattern = nullptr;
u64 m_editingPatternOffset = 0;
TreeStyle m_treeStyle = TreeStyle::Default;
bool m_rowColoring = false;
pl::ptrn::Pattern *m_currVisualizedPattern = nullptr;
std::set<pl::ptrn::Pattern*> m_visualizedPatterns;
std::string m_lastVisualizerError;
2023-06-04 16:13:46 +02:00
std::string m_filterText;
Filter m_filter;
std::vector<std::string> m_currPatternPath;
std::map<std::vector<std::string>, std::unique_ptr<pl::ptrn::Pattern>> m_favorites;
feat: Added hex::group attribute and various fixes (#1302) As discussed (many times) on Discord, does the same as the new favorite tag, but instead allows you to add multiple groups. Initially, this would cause some insane issues with draw/reset (apparantly) fighting eachother in the pattern drawer. After a lot of trial and error, I decided to rewrite the flow that is responsible for calling reset. Now evaluating patterns is the one to decide when the reset happens, not the core "game"-loop. To make sure that draw and reset can never happen at the same time, the mutex originally used for the favorites has been repurposed. Due to the restructuring, the mutex in the favorite-task is no longer needed, as that will only ever kick-off after reset is called and if there are actually patterns, which can never line up to be accessed on different threads at the same time. Last but not least, I noticed that hard crashes could result in your config file getting overridden. I added a check to prevent that. Last I issue I can see is that if you use an excessive amount of favorites/groups, a crash can still happen, but it only happens when you close the program (occasionally, but unpredictable). Before, this would happen if you ran the evaluation a second time. I boiled the cause of the crash down to these lines of code in evaluator.cpp > patternDestroyed: ```cpp if (pattern->isPatternLocal()) { if (auto it = this->m_patternLocalStorage.find(pattern->getHeapAddress()); it != this->m_patternLocalStorage.end()) { auto &[key, data] = *it; data.referenceCount--; if (data.referenceCount == 0) this->m_patternLocalStorage.erase(it); } else if (!this->m_evaluated) { err::E0001.throwError(fmt::format("Double free of variable named '{}'.", pattern->getVariableName())); } } ``` Specifically, trying to access the `*it` is the reason for the crash (this was also the cause of the crashes before my fixes, but then during evaluation). I'm suspecting the root cause is somewhere in the `.clone` methods of the patterns. I'd say that for now a crash when closing the program is more acceptable than during evaluation (which can even happen if you use favorites).
2023-09-16 13:09:59 +02:00
std::map<std::string, std::vector<std::unique_ptr<pl::ptrn::Pattern>>> m_groups;
bool m_showFavoriteStars = false;
bool m_favoritesUpdated = false;
2023-07-23 09:14:00 +02:00
bool m_showSpecName = false;
TaskHolder m_favoritesUpdateTask;
std::function<void(Region)> m_selectionCallback = [](Region) { };
pl::gen::fmt::FormatterArray m_formatters;
};
}