1
0
mirror of synced 2025-02-10 15:52:59 +01:00
ImHex/plugins/builtin/source/content/views/view_pattern_data.cpp

99 lines
4.2 KiB
C++
Raw Normal View History

#include <content/views/view_pattern_data.hpp>
2020-11-10 21:31:04 +01:00
#include <hex/api/content_registry.hpp>
#include <hex/providers/memory_provider.hpp>
impr: Refactor and restructure Event Manager (#2082) ### Problem description This PR addresses issue #2013 that described a cluttered Event Manager. This is a DX issue and should not impact the users whatsoever. ### Implementation description The changes revolve around three main points: 1. the Event Manager (`event_manager.hpp`) was split into four categories: GUI, Interaction, Lifecycle, and Provider, and two types: Events, and Requests. This results in the following files: - `events_gui.hpp` - `events_interaction.hpp` - `events_lifecycle.hpp` - `events_provider.hpp` - `requests_gui.hpp` - `requests_interaction.hpp` - `requests_lifecycle.hpp` - `requests_provider.hpp` 2. Every event and request now has its own piece of documentation, with a `@brief`, accompanied by a longer comment if needed, and gets its `@param`s described. 3. The old `event_manager.hpp` import was removed and replaced by the correct imports wherever needed, as to reduce spread of those files only to where they are truly useful. ### Additional things The commits have been split into (chrono-)logical steps: - `feat`: split the Event Manager, and replace the imports - `refactor`, `chore`: make various small changes to match the required structure - `docs`: add documentation for events and requests Hopefully, this will help to review the PR. *Note: Beware of very long rebuild times in between the commits, use them sparingly! The Actions will ensure this PR builds anyways* Closes #2013 --------- Signed-off-by: BioTheWolff <47079795+BioTheWolff@users.noreply.github.com> Co-authored-by: Nik <werwolv98@gmail.com>
2025-01-25 16:32:07 +01:00
#include <hex/api/events/requests_interaction.hpp>
2024-12-14 20:36:09 +01:00
#include <fonts/vscode_icons.hpp>
#include <pl/patterns/pattern.hpp>
#include <wolv/utils/lock.hpp>
2021-12-07 22:47:41 +01:00
namespace hex::plugin::builtin {
2020-11-10 21:31:04 +01:00
2024-01-08 21:51:48 +01:00
ViewPatternData::ViewPatternData() : View::Window("hex.builtin.view.pattern_data.name", ICON_VS_DATABASE) {
// Handle tree style setting changes
2024-02-18 11:29:18 +01:00
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.pattern_tree_style", [this](const ContentRegistry::Settings::SettingsValue &value) {
m_treeStyle = ui::PatternDrawer::TreeStyle(value.get<int>(0));
for (auto &drawer : m_patternDrawer.all())
drawer->setTreeStyle(m_treeStyle);
2024-02-18 11:29:18 +01:00
});
2024-02-18 11:29:18 +01:00
ContentRegistry::Settings::onChange("hex.builtin.setting.interface", "hex.builtin.setting.interface.pattern_data_row_bg", [this](const ContentRegistry::Settings::SettingsValue &value) {
m_rowColoring = bool(value.get<int>(false));
for (auto &drawer : m_patternDrawer.all())
drawer->enableRowColoring(m_rowColoring);
});
ContentRegistry::Settings::onChange("hex.builtin.setting.general", "hex.builtin.setting.general.pattern_data_max_filter_items", [this](const ContentRegistry::Settings::SettingsValue &value) {
m_maxFilterItems = value.get<u32>(128);
for (auto &drawer : m_patternDrawer.all())
drawer->setMaxFilterDisplayItems(m_maxFilterItems);
});
EventPatternEvaluating::subscribe(this, [this]{
(*m_patternDrawer)->reset();
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
});
EventPatternExecuted::subscribe(this, [this](const auto&){
(*m_patternDrawer)->reset();
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
});
RequestJumpToPattern::subscribe(this, [this](const pl::ptrn::Pattern *pattern) {
(*m_patternDrawer)->jumpToPattern(pattern);
});
ImHexApi::HexEditor::addHoverHighlightProvider([this](const prv::Provider *, u64, size_t) -> std::set<Region> {
return { m_hoveredPatternRegion };
});
m_patternDrawer.setOnCreateCallback([this](const prv::Provider *, auto &drawer) {
drawer = std::make_unique<ui::PatternDrawer>();
drawer->setSelectionCallback([](const pl::ptrn::Pattern *pattern) {
ImHexApi::HexEditor::setSelection(Region(pattern->getOffset(), pattern->getSize()));
RequestPatternEditorSelectionChange::post(pattern->getLine(), 0);
});
drawer->setHoverCallback([this](const pl::ptrn::Pattern *pattern) {
if (pattern == nullptr)
m_hoveredPatternRegion = Region::Invalid();
else
m_hoveredPatternRegion = Region(pattern->getOffset(), pattern->getSize());
});
drawer->setTreeStyle(m_treeStyle);
drawer->enableRowColoring(m_rowColoring);
});
2020-11-10 21:31:04 +01:00
}
ViewPatternData::~ViewPatternData() {
EventPatternEvaluating::unsubscribe(this);
EventPatternExecuted::unsubscribe(this);
2020-11-10 21:31:04 +01:00
}
void ViewPatternData::drawContent() {
// Draw the pattern tree if the provider is valid
if (ImHexApi::Provider::isValid()) {
// Make sure the runtime has finished evaluating and produced valid patterns
auto &runtime = ContentRegistry::PatternLanguage::getRuntime();
const auto height = std::max(ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeightWithSpacing() - (ImGui::GetStyle().FramePadding.y * 2), ImGui::GetTextLineHeightWithSpacing() * 5);
if (*m_patternDrawer != nullptr) {
(*m_patternDrawer)->enablePatternEditing(ImHexApi::Provider::get()->isWritable());
if (!runtime.arePatternsValid()) {
(*m_patternDrawer)->draw({ }, nullptr, height);
} else {
// If the runtime has finished evaluating, draw the patterns
if (TRY_LOCK(ContentRegistry::PatternLanguage::getRuntimeLock())) {
(*m_patternDrawer)->draw(runtime.getPatterns(), &runtime, height);
}
}
2020-11-10 21:31:04 +01:00
}
}
}
}