ui: Added global running tasks progress bar
This commit is contained in:
parent
677036fb9c
commit
891cc42f08
@ -86,4 +86,6 @@ namespace ImGui {
|
||||
void StyleCustomColorsDark();
|
||||
void StyleCustomColorsLight();
|
||||
void StyleCustomColorsClassic();
|
||||
|
||||
void SmallProgressBar(float fraction, float yOffset = 0.0F);
|
||||
}
|
23
external/ImGui/source/imgui_imhex_extensions.cpp
vendored
23
external/ImGui/source/imgui_imhex_extensions.cpp
vendored
@ -492,4 +492,27 @@ namespace ImGui {
|
||||
return pressed;
|
||||
}
|
||||
|
||||
void SmallProgressBar(float fraction, float yOffset) {
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return;
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos + ImVec2(0, yOffset);
|
||||
ImVec2 size = CalcItemSize(ImVec2(100, 5), 100, g.FontSize + style.FramePadding.y * 2.0f);
|
||||
ImRect bb(pos, pos + size);
|
||||
ItemSize(size, 0);
|
||||
if (!ItemAdd(bb, 0))
|
||||
return;
|
||||
|
||||
// Render
|
||||
fraction = ImSaturate(fraction);
|
||||
RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||
bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize));
|
||||
const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y);
|
||||
RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding);
|
||||
}
|
||||
|
||||
}
|
@ -31,7 +31,6 @@ namespace hex::plugin::builtin {
|
||||
|
||||
std::array<ImU64, 256> m_valueCounts = { 0 };
|
||||
bool m_analyzing = false;
|
||||
std::atomic<u64> m_bytesAnalyzed;
|
||||
|
||||
std::pair<u64, u64> m_analyzedRegion = { 0, 0 };
|
||||
|
||||
|
@ -741,9 +741,12 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
size_t fileSize = file.getSize();
|
||||
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.tools.file_tools.shredder.shredding", fileSize);
|
||||
for (const auto &pattern : overwritePattern) {
|
||||
for (u64 offset = 0; offset < fileSize; offset += 3) {
|
||||
file.write(pattern.data(), std::min<u64>(pattern.size(), fileSize - offset));
|
||||
task.update(offset);
|
||||
}
|
||||
|
||||
file.flush();
|
||||
@ -851,8 +854,11 @@ namespace hex::plugin::builtin {
|
||||
return;
|
||||
}
|
||||
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.tools.file_tools.splitter.splitting", file.getSize());
|
||||
u32 index = 1;
|
||||
for (u64 offset = 0; offset < file.getSize(); offset += splitSize) {
|
||||
task.update(offset);
|
||||
|
||||
File partFile(baseOutputPath + hex::format(".{:05}", index), File::Mode::Create);
|
||||
|
||||
if (!partFile.isValid()) {
|
||||
@ -978,9 +984,14 @@ namespace hex::plugin::builtin {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &file : files) {
|
||||
File input(file, File::Mode::Read);
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.tools.file_tools.combiner.combining", files.size());
|
||||
|
||||
u64 fileIndex = 0;
|
||||
for (const auto &file : files) {
|
||||
task.update(fileIndex);
|
||||
fileIndex++;
|
||||
|
||||
File input(file, File::Mode::Read);
|
||||
if (!input.isValid()) {
|
||||
View::showErrorPopup(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, std::filesystem::path(file).filename().string()));
|
||||
return;
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <imgui_internal.h>
|
||||
#include <imgui_imhex_extensions.h>
|
||||
|
||||
#include <atomic>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void addFooterItems() {
|
||||
@ -20,12 +22,43 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
ContentRegistry::Interface::addFooterItem([] {
|
||||
|
||||
static float framerate = 0;
|
||||
if (ImGui::HasSecondPassed()) {
|
||||
framerate = 1.0F / ImGui::GetIO().DeltaTime;
|
||||
}
|
||||
|
||||
ImGui::TextUnformatted(hex::format("FPS {0:2}.{1:02}", u32(framerate), u32(framerate * 100) % 100).c_str());
|
||||
|
||||
});
|
||||
|
||||
ContentRegistry::Interface::addFooterItem([] {
|
||||
size_t taskCount = 0;
|
||||
double taskProgress = 0.0;
|
||||
std::string taskName;
|
||||
|
||||
{
|
||||
std::scoped_lock lock(SharedData::tasksMutex);
|
||||
|
||||
taskCount = SharedData::runningTasks.size();
|
||||
if (taskCount > 0) {
|
||||
taskProgress = SharedData::runningTasks.front()->getProgress();
|
||||
taskName = SharedData::runningTasks.front()->getName();
|
||||
}
|
||||
}
|
||||
|
||||
if (taskCount > 0) {
|
||||
if (taskCount > 0)
|
||||
ImGui::TextSpinner(hex::format("({})", taskCount).c_str());
|
||||
else
|
||||
ImGui::TextSpinner("");
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::SmallProgressBar(taskProgress, (ImGui::GetCurrentWindow()->MenuBarHeight() - 10 * SharedData::globalScale) / 2.0);
|
||||
ImGui::InfoTooltip(taskName.c_str());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -66,7 +66,12 @@ namespace hex::plugin::builtin {
|
||||
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
std::vector<u8> buffer(2048, 0x00);
|
||||
for (u64 address = 0; address < (this->m_codeRegion[1] - this->m_codeRegion[0] + 1); address += 2048) {
|
||||
size_t size = (this->m_codeRegion[1] - this->m_codeRegion[0] + 1);
|
||||
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.view.disassembler.disassembling", size);
|
||||
for (u64 address = 0; address < size; address += 2048) {
|
||||
task.update(address);
|
||||
|
||||
size_t bufferSize = std::min(u64(2048), (this->m_codeRegion[1] - this->m_codeRegion[0] + 1) - address);
|
||||
provider->read(this->m_codeRegion[0] + address, buffer.data(), bufferSize);
|
||||
|
||||
|
@ -71,8 +71,19 @@ namespace hex::plugin::builtin {
|
||||
std::thread([this]{
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.view.information.analyzing", provider->getSize());
|
||||
|
||||
this->m_analyzedRegion = { provider->getBaseAddress(), provider->getBaseAddress() + provider->getSize() };
|
||||
|
||||
{
|
||||
magic::compile();
|
||||
|
||||
this->m_fileDescription = magic::getDescription(provider);
|
||||
this->m_mimeType = magic::getMIMEType(provider);
|
||||
}
|
||||
|
||||
this->m_dataValid = true;
|
||||
|
||||
{
|
||||
this->m_blockSize = std::max<u32>(std::ceil(provider->getSize() / 2048.0F), 256);
|
||||
std::vector<u8> buffer(this->m_blockSize, 0x00);
|
||||
@ -90,22 +101,13 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
this->m_blockEntropy.push_back(calculateEntropy(blockValueCounts, this->m_blockSize));
|
||||
|
||||
this->m_bytesAnalyzed = i;
|
||||
task.update(i);
|
||||
}
|
||||
|
||||
this->m_averageEntropy = calculateEntropy(this->m_valueCounts, provider->getSize());
|
||||
this->m_highestBlockEntropy = *std::max_element(this->m_blockEntropy.begin(), this->m_blockEntropy.end());
|
||||
}
|
||||
|
||||
{
|
||||
magic::compile();
|
||||
|
||||
this->m_fileDescription = magic::getDescription(provider);
|
||||
this->m_mimeType = magic::getMIMEType(provider);
|
||||
this->m_dataValid = true;
|
||||
}
|
||||
|
||||
this->m_analyzing = false;
|
||||
}).detach();
|
||||
}
|
||||
@ -127,10 +129,8 @@ namespace hex::plugin::builtin {
|
||||
|
||||
if (this->m_analyzing) {
|
||||
ImGui::TextSpinner("hex.builtin.view.information.analyzing"_lang);
|
||||
ImGui::ProgressBar(this->m_bytesAnalyzed / static_cast<double>(provider->getSize()));
|
||||
} else {
|
||||
ImGui::NewLine();
|
||||
ImGui::NewLine();
|
||||
}
|
||||
|
||||
ImGui::NewLine();
|
||||
|
@ -384,6 +384,8 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
void ViewPatternEditor::drawAlwaysVisible() {
|
||||
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
|
||||
if (ImGui::BeginPopupModal("hex.builtin.view.pattern_editor.accept_pattern"_lang, &this->m_acceptPatternWindowOpen, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::TextWrapped("%s", static_cast<const char *>("hex.builtin.view.pattern_editor.accept_pattern.desc"_lang));
|
||||
|
||||
@ -423,6 +425,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
bool opened = true;
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
|
||||
if (ImGui::BeginPopupModal("hex.builtin.view.pattern_editor.menu.file.load_pattern"_lang, &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
|
||||
if (ImGui::BeginListBox("##patterns", ImVec2(-FLT_MIN, 0))) {
|
||||
|
@ -65,16 +65,19 @@ namespace hex::plugin::builtin {
|
||||
|
||||
std::thread([this] {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.view.strings.searching", provider->getActualSize());
|
||||
|
||||
std::vector<u8> buffer(1024, 0x00);
|
||||
u32 foundCharacters = 0;
|
||||
|
||||
for (u64 offset = 0; offset < provider->getSize(); offset += buffer.size()) {
|
||||
size_t readSize = std::min(u64(buffer.size()), provider->getSize() - offset);
|
||||
for (u64 offset = 0; offset < provider->getActualSize(); offset += buffer.size()) {
|
||||
task.update(offset);
|
||||
|
||||
size_t readSize = std::min(u64(buffer.size()), provider->getActualSize() - offset);
|
||||
provider->read(offset + provider->getBaseAddress(), buffer.data(), readSize);
|
||||
|
||||
for (u32 i = 0; i < readSize; i++) {
|
||||
if (buffer[i] >= ' ' && buffer[i] <= '~' && offset < provider->getSize() - 1)
|
||||
if (buffer[i] >= ' ' && buffer[i] <= '~' && offset < provider->getActualSize() - 1)
|
||||
foundCharacters++;
|
||||
else {
|
||||
if (foundCharacters >= this->m_minimumLength) {
|
||||
|
@ -144,6 +144,10 @@ namespace hex::plugin::builtin {
|
||||
this->m_matching = true;
|
||||
|
||||
std::thread([this] {
|
||||
if (!ImHexApi::Provider::isValid()) return;
|
||||
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.view.yara.matching", provider->getActualSize());
|
||||
|
||||
YR_COMPILER *compiler = nullptr;
|
||||
yr_compiler_create(&compiler);
|
||||
@ -192,11 +196,13 @@ namespace hex::plugin::builtin {
|
||||
YR_MEMORY_BLOCK_ITERATOR iterator;
|
||||
|
||||
struct ScanContext {
|
||||
Task *task;
|
||||
std::vector<u8> buffer;
|
||||
YR_MEMORY_BLOCK currBlock;
|
||||
};
|
||||
|
||||
ScanContext context;
|
||||
context.task = &task;
|
||||
context.currBlock.base = 0;
|
||||
context.currBlock.fetch_data = [](auto *block) -> const u8* {
|
||||
auto &context = *static_cast<ScanContext*>(block->context);
|
||||
@ -237,6 +243,7 @@ namespace hex::plugin::builtin {
|
||||
context.currBlock.base = address;
|
||||
context.currBlock.size = ImHexApi::Provider::get()->getActualSize() - address;
|
||||
context.currBlock.context = &context;
|
||||
context.task->update(address);
|
||||
|
||||
if (context.currBlock.size == 0) return nullptr;
|
||||
|
||||
|
@ -92,6 +92,7 @@ set(LIBIMHEX_SOURCES
|
||||
source/api/event.cpp
|
||||
source/api/imhex_api.cpp
|
||||
source/api/content_registry.cpp
|
||||
source/api/task.cpp
|
||||
|
||||
source/data_processor/attribute.cpp
|
||||
source/data_processor/link.cpp
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <string>
|
||||
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/api/task.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@ -15,7 +16,6 @@ namespace hex {
|
||||
namespace ImHexApi {
|
||||
namespace Common {
|
||||
|
||||
void sayHello();
|
||||
void closeImHex(bool noQuestions = false);
|
||||
void restartImHex();
|
||||
|
||||
@ -55,6 +55,12 @@ namespace hex {
|
||||
|
||||
};
|
||||
|
||||
namespace Tasks {
|
||||
|
||||
Task createTask(const std::string &unlocalizedName, u64 maxValue);
|
||||
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
28
plugins/libimhex/include/hex/api/task.hpp
Normal file
28
plugins/libimhex/include/hex/api/task.hpp
Normal file
@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class Task {
|
||||
public:
|
||||
Task(const std::string& unlocalizedName, u64 maxValue);
|
||||
~Task();
|
||||
|
||||
void update(u64 currValue);
|
||||
void finish();
|
||||
|
||||
[[nodiscard]]
|
||||
double getProgress() const;
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& getName() const;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
u64 m_maxValue, m_currValue;
|
||||
};
|
||||
|
||||
}
|
@ -5,10 +5,12 @@
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/task.hpp>
|
||||
#include <hex/views/view.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
@ -77,6 +79,9 @@ namespace hex {
|
||||
static std::vector<ContentRegistry::Interface::DrawCallback> footerItems;
|
||||
static std::vector<ContentRegistry::Interface::DrawCallback> toolbarItems;
|
||||
|
||||
static std::mutex tasksMutex;
|
||||
static std::list<Task*> runningTasks;
|
||||
|
||||
static std::vector<std::string> providerNames;
|
||||
|
||||
static std::vector<ContentRegistry::DataProcessorNode::impl::Entry> dataProcessorNodes;
|
||||
|
@ -9,10 +9,6 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
void ImHexApi::Common::sayHello() {
|
||||
log::warn("Hello!");
|
||||
}
|
||||
|
||||
void ImHexApi::Common::closeImHex(bool noQuestions) {
|
||||
EventManager::post<RequestCloseImHex>(noQuestions);
|
||||
}
|
||||
@ -85,4 +81,9 @@ namespace hex {
|
||||
delete provider;
|
||||
}
|
||||
|
||||
|
||||
Task ImHexApi::Tasks::createTask(const std::string &unlocalizedName, u64 maxValue) {
|
||||
return Task(unlocalizedName, maxValue);
|
||||
}
|
||||
|
||||
}
|
32
plugins/libimhex/source/api/task.cpp
Normal file
32
plugins/libimhex/source/api/task.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include <hex/api/task.hpp>
|
||||
|
||||
#include <hex/helpers/shared_data.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
Task::Task(const std::string& unlocalizedName, u64 maxValue) : m_name(LangEntry(unlocalizedName)), m_maxValue(maxValue), m_currValue(0) {
|
||||
SharedData::runningTasks.push_back(this);
|
||||
}
|
||||
|
||||
Task::~Task() {
|
||||
this->finish();
|
||||
}
|
||||
|
||||
void Task::finish() {
|
||||
SharedData::runningTasks.remove(this);
|
||||
}
|
||||
|
||||
void Task::update(u64 currValue) {
|
||||
if (this->m_currValue < this->m_maxValue)
|
||||
this->m_currValue = currValue;
|
||||
}
|
||||
|
||||
double Task::getProgress() const {
|
||||
return static_cast<double>(this->m_currValue) / static_cast<double>(this->m_maxValue);
|
||||
}
|
||||
|
||||
const std::string& Task::getName() const {
|
||||
return this->m_name;
|
||||
}
|
||||
|
||||
}
|
@ -29,6 +29,9 @@ namespace hex {
|
||||
std::vector<ContentRegistry::Interface::DrawCallback> SharedData::footerItems;
|
||||
std::vector<ContentRegistry::Interface::DrawCallback> SharedData::toolbarItems;
|
||||
|
||||
std::mutex SharedData::tasksMutex;
|
||||
std::list<Task*> SharedData::runningTasks;
|
||||
|
||||
std::vector<std::string> SharedData::providerNames;
|
||||
|
||||
std::vector<ContentRegistry::DataProcessorNode::impl::Entry> SharedData::dataProcessorNodes;
|
||||
|
@ -279,15 +279,17 @@ namespace hex {
|
||||
}
|
||||
|
||||
void Window::loop() {
|
||||
double timeout;
|
||||
this->m_lastFrameTime = glfwGetTime();
|
||||
while (!glfwWindowShouldClose(this->m_window)) {
|
||||
if (!glfwGetWindowAttrib(this->m_window, GLFW_VISIBLE) || glfwGetWindowAttrib(this->m_window, GLFW_ICONIFIED))
|
||||
if (!glfwGetWindowAttrib(this->m_window, GLFW_VISIBLE) || glfwGetWindowAttrib(this->m_window, GLFW_ICONIFIED)) {
|
||||
glfwWaitEvents();
|
||||
else
|
||||
timeout = (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime);
|
||||
|
||||
} else {
|
||||
double timeout = (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime);
|
||||
timeout = timeout > 0 ? timeout : 0;
|
||||
glfwWaitEventsTimeout(ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) ? 0 : timeout);
|
||||
glfwWaitEventsTimeout(ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || !SharedData::runningTasks.empty() ? 0 : timeout);
|
||||
}
|
||||
|
||||
|
||||
this->frameBegin();
|
||||
this->frame();
|
||||
|
Loading…
x
Reference in New Issue
Block a user