Added some utility coroutines for showing message boxes.

This commit is contained in:
Patrick Wuttke 2025-09-23 11:14:33 +02:00
parent 69fdae991a
commit d56918e71d

View File

@ -6,12 +6,14 @@
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <format>
#include <functional> #include <functional>
#include <span> #include <span>
#include <string> #include <string>
#include <vector> #include <vector>
#include <imgui.h> #include <imgui.h>
#include <mijin/async/coroutine.hpp>
#include <mijin/debug/assert.hpp> #include <mijin/debug/assert.hpp>
namespace ImRaid namespace ImRaid
@ -231,6 +233,92 @@ inline DataTableColumn<TObject> MakeColumn(const char* header, const char* fmt,
.comparator = [member](const TObject& left, const TObject& right) { return left.*member < right.*member; } .comparator = [member](const TObject& left, const TObject& right) { return left.*member < right.*member; }
}; };
} }
template<typename TFunc>
mijin::Task<> c_MessageBox(const char* titleId, TFunc&& renderFunc)
{
ImGui::OpenPopup(titleId);
bool open = true;
while (ImGui::BeginPopupModal(titleId, &open, ImGuiWindowFlags_NoResize))
{
std::invoke(std::forward<TFunc>(renderFunc));
ImGui::EndPopup();
co_await mijin::c_suspend();
}
}
template<typename... TFormatArgs>
mijin::Task<int> c_MessageBox(const char* titleId, std::span<const char*> buttons, std::format_string<TFormatArgs...> format, TFormatArgs&&... formatArgs)
{
const std::string message = std::format(format, std::forward<TFormatArgs>(formatArgs)...);
int buttonIdx = -1;
const ImGuiStyle& style = ImGui::GetStyle();
float buttonsWidth = 0.f;
for (const char* button : buttons) {
buttonsWidth += ImGui::CalcTextSize(button).x;
}
buttonsWidth += static_cast<float>(buttons.size()) * 2.f * style.FramePadding.x;;
buttonsWidth += static_cast<float>(buttons.size() - 1) * style.ItemSpacing.x;
co_await c_MessageBox(titleId, [&]()
{
ImGui::TextUnformatted(message.c_str());
const float offset = 0.5f * (ImGui::GetWindowWidth() - buttonsWidth);
ImGui::SetCursorPosX(offset);
for (int idx = 0; idx < static_cast<int>(buttons.size()); ++idx)
{
if (idx != 0) {
ImGui::SameLine();
}
if (ImGui::Button(buttons[idx]))
{
buttonIdx = idx;
ImGui::CloseCurrentPopup();
}
}
});
co_return buttonIdx;
}
struct YesNo
{
enum Value
{
YES,
NO
};
Value value = Value::NO;
constexpr YesNo() noexcept = default;
constexpr YesNo(const YesNo&) noexcept = default;
constexpr YesNo(Value value_) noexcept : value(value_) {}
constexpr YesNo& operator=(const YesNo&) noexcept = default;
constexpr auto operator<=>(const YesNo&) const noexcept = default;
constexpr operator bool() const noexcept { return value == YES; }
constexpr bool operator!() const noexcept { return value == NO; }
};
template<YesNo::Value DefaultResult = YesNo::NO, typename... TFormatArgs>
mijin::Task<YesNo> c_MessageBoxYesNo(const char* titleId, std::format_string<TFormatArgs...> format, TFormatArgs&&... formatArgs)
{
static std::array<const char*, 2> BUTTONS = {"Yes", "No"};
const int idx = co_await c_MessageBox(titleId, BUTTONS, format, std::forward<TFormatArgs>(formatArgs)...);
switch (idx)
{
case 0:
co_return YesNo::YES;
case 1:
co_return YesNo::NO;
default:
co_return DefaultResult;
}
}
} // namespace ImRaid } // namespace ImRaid
#endif // !defined(RAID_PUBLIC_RAID_IMRAID_HPP_INCLUDED) #endif // !defined(RAID_PUBLIC_RAID_IMRAID_HPP_INCLUDED)