Compare commits

...

2 Commits

3 changed files with 104 additions and 0 deletions

View File

@ -339,6 +339,11 @@ void Application::handleSDLEvent(const SDL_Event& event)
case SDL_EVENT_QUIT: case SDL_EVENT_QUIT:
mRunning = false; mRunning = false;
return; return;
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
if (SDL_GetWindowFromID(event.window.windowID) == mWindow) {
handleCloseRequested();
}
break;
default: default:
ImGui_ImplSDL3_ProcessEvent(&event); ImGui_ImplSDL3_ProcessEvent(&event);
break; break;
@ -350,6 +355,13 @@ void Application::handleSDLError(const char* message)
msgError("SDL: {}", message); msgError("SDL: {}", message);
} }
void Application::handleCloseRequested()
{
SDL_Event quitEvent;
quitEvent.type = SDL_EVENT_QUIT;
SDL_PushEvent(&quitEvent);
}
bool Application::init() bool Application::init()
{ {
auto addConfigDir = [&](const fs::path& path) auto addConfigDir = [&](const fs::path& path)
@ -516,6 +528,8 @@ bool Application::initSDL()
return false; return false;
} }
SDL_SetHint(SDL_HINT_QUIT_ON_LAST_WINDOW_CLOSE, "0"); // let us handle ourselves
msgInfo("SDL video driver: {}", SDL_GetCurrentVideoDriver()); msgInfo("SDL video driver: {}", SDL_GetCurrentVideoDriver());
SDL_WindowFlags windowFlags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY; SDL_WindowFlags windowFlags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY;

View File

@ -152,6 +152,8 @@ protected:
virtual void handleSDLEvent(const SDL_Event& event); virtual void handleSDLEvent(const SDL_Event& event);
virtual void handleSDLError(const char* message); virtual void handleSDLError(const char* message);
virtual void handleCloseRequested();
void msgInfo(const char* text) void msgInfo(const char* text)
{ {
handleMessage({ handleMessage({

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)