diff --git a/src/Magnum/ImGuiIntegration/Context.cpp b/src/Magnum/ImGuiIntegration/Context.cpp index 00438bd4..9ac0c128 100644 --- a/src/Magnum/ImGuiIntegration/Context.cpp +++ b/src/Magnum/ImGuiIntegration/Context.cpp @@ -85,7 +85,7 @@ Context::Context(ImGuiContext& context, const Vector2& size, const Vector2i& win /* Tell ImGui that changing mouse cursors is supported */ io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors; - + /* Check if we can support base vertex > 0 in draw commands */ #if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2)) if( @@ -312,17 +312,17 @@ void Context::drawFrame() { ImGui::Render(); - ImGuiIO& io = ImGui::GetIO(); - const Vector2 fbSize = Vector2{io.DisplaySize}*Vector2{io.DisplayFramebufferScale}; - if(!fbSize.product()) return; - ImDrawData* drawData = ImGui::GetDrawData(); CORRADE_INTERNAL_ASSERT(drawData); /* This is always valid after Render() */ - drawData->ScaleClipRects(io.DisplayFramebufferScale); + + const Vector2 fbSize = Vector2{drawData->DisplaySize}*Vector2{drawData->FramebufferScale}; + if(!fbSize.product()) return; + + drawData->ScaleClipRects(drawData->FramebufferScale); const Matrix3 projection = Matrix3::translation({-1.0f, 1.0f})* - Matrix3::scaling({2.0f/Vector2(io.DisplaySize)})* + Matrix3::scaling({2.0f/Vector2(drawData->DisplaySize)})* Matrix3::scaling({1.0f, -1.0f}); _shader.setTransformationProjectionMatrix(projection); diff --git a/src/Magnum/ImGuiIntegration/Context.h b/src/Magnum/ImGuiIntegration/Context.h index d4795089..36fe58ed 100644 --- a/src/Magnum/ImGuiIntegration/Context.h +++ b/src/Magnum/ImGuiIntegration/Context.h @@ -378,6 +378,20 @@ class MAGNUM_IMGUIINTEGRATION_EXPORT Context { */ explicit Context(ImGuiContext& context, const Vector2i& size); + /** + * @brief TODO + * + * Implicitly fetches framebuffer and window size from the application instance + * Using this template constructor is preferable as it enables additional features based on given Application capabilities + */ + template explicit Context(const Vector2& size, const Application& application); + + /** + * @brief TODO + * + */ + template explicit Context(ImGuiContext& context, const Vector2& size, const Application& application); + /** * @brief Construct without creating the underlying ImGui context * diff --git a/src/Magnum/ImGuiIntegration/Context.hpp b/src/Magnum/ImGuiIntegration/Context.hpp index 5d3382cd..835526f8 100644 --- a/src/Magnum/ImGuiIntegration/Context.hpp +++ b/src/Magnum/ImGuiIntegration/Context.hpp @@ -45,6 +45,20 @@ #include "Magnum/ImGuiIntegration/Context.h" namespace Magnum { namespace ImGuiIntegration { +namespace Implementation { + template + constexpr static bool hasWarpCursor(const Application&) { return true; } + + template constexpr static bool hasWarpCursor(const T&...) { return false; } +} + +template Context::Context(const Vector2& size, const Application& application): Context{*ImGui::CreateContext(), size, application} {} + +template Context::Context(ImGuiContext& context, const Vector2& size, const Application& application): Context{context, size, application.windowSize(), application.framebufferSize()} { + /* We can honor io.WantSetMousePos requests if application type supports it */ + if(Implementation::hasWarpCursor(application)) + ImGui::GetIO().BackendFlags |= ImGuiBackendFlags_HasSetMousePos; +} template bool Context::handleKeyEvent(KeyEvent& event, bool value) { /* Ensure we use the context we're linked to */ @@ -337,12 +351,24 @@ MAGNUM_IMGUIINTEGRATION_OPTIONAL_CURSOR(No) #undef MAGNUM_IMGUIINTEGRATION_OPTIONAL_CURSOR #endif + template static void callWarpCursor(const T&...) {} + + template + static void callWarpCursor(Application& application, const Vector2i& position) { + application.warpCursor(position); + } } template void Context::updateApplicationCursor(Application& application) { /* Ensure we use the context we're linked to */ ImGui::SetCurrentContext(_context); + ImGuiIO& io = ImGui::GetIO(); + + if(io.WantSetMousePos) { + Implementation::callWarpCursor(application, Vector2i(Vector2(io.MousePos)/_eventScaling)); + } + switch(ImGui::GetMouseCursor()) { case ImGuiMouseCursor_TextInput: application.setCursor(Application::Cursor::TextInput); diff --git a/src/Magnum/ImGuiIntegration/Test/ContextGLTest.cpp b/src/Magnum/ImGuiIntegration/Test/ContextGLTest.cpp index 9228deb8..28bd8aa5 100644 --- a/src/Magnum/ImGuiIntegration/Test/ContextGLTest.cpp +++ b/src/Magnum/ImGuiIntegration/Test/ContextGLTest.cpp @@ -114,8 +114,11 @@ struct Application { None = 999 }; - void setCursor(Cursor cursor) { currentCursor = cursor; } Cursor currentCursor = Cursor::None; + Vector2i mousePos; + + void setCursor(Cursor cursor) { currentCursor = cursor; } + void warpCursor(const Vector2i& pos) { mousePos = pos; } }; struct KeyEvent: public InputEvent { @@ -752,7 +755,7 @@ void ContextGLTest::textInput() { } void ContextGLTest::updateCursor() { - Context c{{}}; + Context c{{200, 200}, {400, 400}, {300, 300}}; Application app; @@ -780,6 +783,26 @@ void ContextGLTest::updateCursor() { ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNESW); c.updateApplicationCursor(app); CORRADE_VERIFY(app.currentCursor == Application::Cursor::Arrow); + + /* Change to imgui mouse pos and mark it as changed + Account for 2x DPI scaling in equality check */ + ImGuiIO& io = ImGui::GetIO(); + io.MousePos = ImVec2(10, 15); + io.WantSetMousePos = true; + c.updateApplicationCursor(app); + CORRADE_VERIFY(app.mousePos == Vector2i(20, 30)); + + /* Change to imgui mouse pos without marking it as changed */ + io.MousePos = ImVec2(50, 0); + io.WantSetMousePos = false; + c.updateApplicationCursor(app); + CORRADE_VERIFY(app.mousePos == Vector2i(20, 30)); + + /* Mark mouse pos changed */ + io.WantSetMousePos = true; + c.updateApplicationCursor(app); + CORRADE_VERIFY(app.mousePos == Vector2i(100, 0)); + } void ContextGLTest::multipleContexts() {