1
0
mirror of synced 2025-02-02 12:27:25 +01:00

feat: Added blocking tasks that show a full-screen modal when active

This commit is contained in:
WerWolv 2025-02-02 11:24:28 +01:00
parent 06c019387c
commit 19f9296a40
6 changed files with 98 additions and 15 deletions

View File

@ -22,7 +22,7 @@ namespace hex {
class Task {
public:
Task() = default;
Task(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
Task(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, bool blocking, std::function<void(Task &)> function);
Task(const Task&) = delete;
Task(Task &&other) noexcept;
@ -57,6 +57,7 @@ namespace hex {
void setInterruptCallback(std::function<void()> callback);
[[nodiscard]] bool isBackgroundTask() const;
[[nodiscard]] bool isBlocking() const;
[[nodiscard]] bool isFinished() const;
[[nodiscard]] bool hadException() const;
[[nodiscard]] bool wasInterrupted() const;
@ -84,6 +85,7 @@ namespace hex {
std::atomic<bool> m_shouldInterrupt = false;
std::atomic<bool> m_background = true;
std::atomic<bool> m_blocking = false;
std::atomic<bool> m_interrupted = false;
std::atomic<bool> m_finished = false;
@ -162,6 +164,24 @@ namespace hex {
*/
static TaskHolder createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void()> function);
/**
* @brief Creates a new asynchronous task that shows a blocking modal window
* @param unlocalizedName Name of the task
* @param maxValue Maximum value of the task
* @param function Function to be executed
* @return A TaskHolder holding a weak reference to the task
*/
static TaskHolder createBlockingTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void(Task &)> function);
/**
* @brief Creates a new asynchronous task that shows a blocking modal window
* @param unlocalizedName Name of the task
* @param maxValue Maximum value of the task
* @param function Function to be executed
* @return A TaskHolder holding a weak reference to the task
*/
static TaskHolder createBlockingTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void()> function);
/**
* @brief Creates a new synchronous task that will execute the given function at the start of the next frame
* @param function Function to be executed
@ -202,12 +222,13 @@ namespace hex {
static size_t getRunningTaskCount();
static size_t getRunningBackgroundTaskCount();
static size_t getRunningBlockingTaskCount();
static const std::list<std::shared_ptr<Task>>& getRunningTasks();
static void runDeferredCalls();
private:
static TaskHolder createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
static TaskHolder createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, bool blocking, std::function<void(Task &)> function);
};
}

View File

@ -184,7 +184,7 @@ namespace ImGuiExt {
void StyleCustomColorsLight();
void StyleCustomColorsClassic();
void SmallProgressBar(float fraction, float yOffset = 0.0F);
void ProgressBar(float fraction, ImVec2 size_value = ImVec2(0, 0), float yOffset = 0.0F);
inline void TextFormatted(std::string_view fmt, auto &&...args) {
if constexpr (sizeof...(args) == 0) {

View File

@ -63,8 +63,11 @@ namespace hex {
}
Task::Task(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function)
: m_unlocalizedName(std::move(unlocalizedName)), m_maxValue(maxValue), m_function(std::move(function)), m_background(background) { }
Task::Task(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, bool blocking, std::function<void(Task &)> function)
: m_unlocalizedName(std::move(unlocalizedName)),
m_maxValue(maxValue),
m_function(std::move(function)),
m_background(background), m_blocking(blocking) { }
Task::Task(hex::Task &&other) noexcept {
{
@ -133,6 +136,11 @@ namespace hex {
return m_background;
}
bool Task::isBlocking() const {
return m_blocking;
}
bool Task::isFinished() const {
return m_finished;
}
@ -327,11 +335,11 @@ namespace hex {
s_tasksFinishedCallbacks.clear();
}
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task&)> function) {
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, bool blocking, std::function<void(Task&)> function) {
std::scoped_lock lock(s_queueMutex);
// Construct new task
auto task = std::make_shared<Task>(std::move(unlocalizedName), maxValue, background, std::move(function));
auto task = std::make_shared<Task>(std::move(unlocalizedName), maxValue, background, blocking, std::move(function));
s_tasks.emplace_back(task);
@ -346,12 +354,12 @@ namespace hex {
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void(Task &)> function) {
log::debug("Creating task {}", unlocalizedName.get());
return createTask(std::move(unlocalizedName), maxValue, false, std::move(function));
return createTask(std::move(unlocalizedName), maxValue, false, false, std::move(function));
}
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void()> function) {
log::debug("Creating task {}", unlocalizedName.get());
return createTask(std::move(unlocalizedName), maxValue, false,
return createTask(std::move(unlocalizedName), maxValue, false, false,
[function = std::move(function)](Task&) {
function();
}
@ -360,12 +368,26 @@ namespace hex {
TaskHolder TaskManager::createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void(Task &)> function) {
log::debug("Creating background task {}", unlocalizedName.get());
return createTask(std::move(unlocalizedName), 0, true, std::move(function));
return createTask(std::move(unlocalizedName), 0, true, false, std::move(function));
}
TaskHolder TaskManager::createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void()> function) {
log::debug("Creating background task {}", unlocalizedName.get());
return createTask(std::move(unlocalizedName), 0, true,
return createTask(std::move(unlocalizedName), 0, true, false,
[function = std::move(function)](Task&) {
function();
}
);
}
TaskHolder TaskManager::createBlockingTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void(Task &)> function) {
log::debug("Creating blocking task {}", unlocalizedName.get());
return createTask(std::move(unlocalizedName), maxValue, true, true, std::move(function));
}
TaskHolder TaskManager::createBlockingTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void()> function) {
log::debug("Creating blocking task {}", unlocalizedName.get());
return createTask(std::move(unlocalizedName), maxValue, true, true,
[function = std::move(function)](Task&) {
function();
}
@ -414,6 +436,14 @@ namespace hex {
});
}
size_t TaskManager::getRunningBlockingTaskCount() {
std::scoped_lock lock(s_queueMutex);
return std::ranges::count_if(s_tasks, [](const auto &task){
return task->isBlocking();
});
}
void TaskManager::doLater(const std::function<void()> &function) {
std::scoped_lock lock(s_deferredCallsMutex);

View File

@ -941,7 +941,7 @@ namespace ImGuiExt {
return result;
}
void SmallProgressBar(float fraction, float yOffset) {
void ProgressBar(float fraction, ImVec2 size_value, float yOffset) {
ImGuiWindow *window = GetCurrentWindow();
if (window->SkipItems)
return;
@ -950,7 +950,7 @@ namespace ImGuiExt {
const ImGuiStyle &style = g.Style;
ImVec2 pos = window->DC.CursorPos + ImVec2(0, yOffset);
ImVec2 size = CalcItemSize(ImVec2(100, 5) * hex::ImHexApi::System::getGlobalScale(), 100, g.FontSize + style.FramePadding.y * 2.0F);
ImVec2 size = CalcItemSize(size_value, ImGui::GetContentRegionAvail().x, g.FontSize + style.FramePadding.y * 2.0F);
ImRect bb(pos, pos + size);
ItemSize(size, 0);
if (!ItemAdd(bb, 0))

View File

@ -393,6 +393,7 @@
"hex.builtin.popup.waiting_for_tasks.title": "Waiting for Tasks",
"hex.builtin.popup.crash_recover.title": "Crash recovery",
"hex.builtin.popup.crash_recover.message": "An exception was thrown, but ImHex was able to catch it and advert a crash",
"hex.builtin.popup.foreground_task.title": "Please Wait...",
"hex.builtin.popup.blocking_task.title": "Running Task",
"hex.builtin.popup.blocking_task.desc": "A task is currently executing.",
"hex.builtin.popup.save_layout.title": "Save Layout",

View File

@ -51,6 +51,33 @@ namespace hex::plugin::builtin {
break;
}
}
if (TaskManager::getRunningBlockingTaskCount() > 0) {
auto tasks = TaskManager::getRunningTasks();
ImGui::SetNextWindowSize(scaled({ 300, 200 }), ImGuiCond_Always);
ImGui::SetNextWindowPos(ImHexApi::System::getMainWindowPosition() + ImHexApi::System::getMainWindowSize() / 2, ImGuiCond_Always, ImVec2(0.5F, 0.5F));
if (ImGui::BeginPopupModal("hex.builtin.popup.foreground_task.title"_lang, nullptr, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) {
for (const auto &task : tasks) {
if (task->isBlocking()) {
ImGui::NewLine();
ImGui::TextUnformatted(Lang(task->getUnlocalizedName()));
ImGui::NewLine();
ImGui::SetCursorPosX((ImGui::GetWindowWidth() - ImGui::CalcTextSize("[-]").x) / 2);
ImGuiExt::TextSpinner("");
ImGui::NewLine();
const auto progress = task->getMaxValue() == 0 ? -1 : float(task->getValue()) / float(task->getMaxValue());
ImGuiExt::ProgressBar(progress, ImVec2(0, 10_scaled));
break;
}
}
ImGui::EndPopup();
} else {
ImGui::OpenPopup("hex.builtin.popup.foreground_task.title"_lang);
}
}
}
static void drawDebugPopup() {
@ -257,7 +284,7 @@ namespace hex::plugin::builtin {
{
ImGuiExt::TextSpinner(hex::format("({})", taskCount).c_str());
ImGui::SameLine();
ImGuiExt::SmallProgressBar(progress, (ImGui::GetCurrentWindowRead()->MenuBarHeight - 10_scaled) / 2.0);
ImGuiExt::ProgressBar(progress, scaled({ 100, 5 }), (ImGui::GetCurrentWindowRead()->MenuBarHeight - 10_scaled) / 2.0);
ImGui::SameLine();
}
const auto widgetEnd = ImGui::GetCursorPos();
@ -284,7 +311,11 @@ namespace hex::plugin::builtin {
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
ImGuiExt::SmallProgressBar(task->getMaxValue() == 0 ? -1 : (float(task->getValue()) / float(task->getMaxValue())), (ImGui::GetTextLineHeightWithSpacing() - 5_scaled) / 2);
ImGuiExt::ProgressBar(
task->getMaxValue() == 0 ? -1 : (float(task->getValue()) / float(task->getMaxValue())),
scaled({ 100, 5 }),
(ImGui::GetTextLineHeightWithSpacing() - 5_scaled) / 2
);
ImGui::SameLine();
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));