Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ImGui: Add support for ImGuiBackendFlags_HasSetMousePos and cleaner drawFrame() code #102

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 8 additions & 6 deletions src/Magnum/ImGuiIntegration/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ Context::Context(ImGuiContext& context, const Vector2& size, const Vector2i& win

/* Tell ImGui that changing mouse cursors is supported */
io.BackendFlags |= ImGuiBackendFlags_HasMouseCursors;
/* We can honor io.WantSetMousePos requests */
io.BackendFlags |= ImGuiBackendFlags_HasSetMousePos;

/* Check if we can support base vertex > 0 in draw commands */
#if !(defined(MAGNUM_TARGET_WEBGL) && defined(MAGNUM_TARGET_GLES2))
Expand Down Expand Up @@ -312,17 +314,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};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, I can't tell if this is a good or a bad change as my knowledge of ImGui is rather bad 😅 How does drawData->FramebufferScale and io.DisplayFramebufferScale relate?

Cc: @pezcode, you're responsible for most of the code here I think, and I bet you know better than me :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the ImGui comments:

ImVec2          DisplayPos;             // Top-left position of the viewport to render (== top-left of the orthogonal projection matrix to use) (== GetMainViewport()->Pos for the main viewport, == (0.0) in most single-viewport applications)
ImVec2          DisplaySize;            // Size of the viewport to render (== GetMainViewport()->Size for the main viewport, == io.DisplaySize in most single-viewport applications)
ImVec2          FramebufferScale;       // Amount of pixels for each unit of DisplaySize. Based on io.DisplayFramebufferScale. Generally (1,1) on normal display, (2,2) on OSX with Retina display.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's mainly to aid with multi-window rendering 😉

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see, that makes sense then :)

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);

Expand Down
12 changes: 12 additions & 0 deletions src/Magnum/ImGuiIntegration/Context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -337,12 +337,24 @@ MAGNUM_IMGUIINTEGRATION_OPTIONAL_CURSOR(No)
#undef MAGNUM_IMGUIINTEGRATION_OPTIONAL_CURSOR
#endif

template<class... T> void callWarpCursor(const T&...) {}

template<class Application, class = decltype(&Application::warpCursor)>
void callWarpCursor(Application& application, const Vector2i& position) {
application.warpCursor(position);
}
}

template<class Application> 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);
Expand Down
39 changes: 31 additions & 8 deletions src/Magnum/ImGuiIntegration/Test/ContextGLTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,11 @@ struct Application {
None = 999
};

void setCursor(Cursor cursor) { currentCursor = cursor; }
Cursor currentCursor = Cursor::None;
Cursor _currentCursor = Cursor::None;
Vector2i _mousePos;
Auburn marked this conversation as resolved.
Show resolved Hide resolved

void setCursor(Cursor cursor) { _currentCursor = cursor; }
void warpCursor(const Vector2i& pos) { _mousePos = pos; }
};

struct KeyEvent: public InputEvent {
Expand Down Expand Up @@ -752,34 +755,54 @@ void ContextGLTest::textInput() {
}

void ContextGLTest::updateCursor() {
Context c{{}};
Context c{{200, 200}, {400, 400}, {300, 300}};

Application app;

/* Default (should be an arrow) */
c.updateApplicationCursor(app);
CORRADE_VERIFY(app.currentCursor == Application::Cursor::Arrow);
CORRADE_VERIFY(app._currentCursor == Application::Cursor::Arrow);

/* Change to a cursor that is present in all apps */
ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
c.updateApplicationCursor(app);
CORRADE_VERIFY(app.currentCursor == Application::Cursor::Hand);
CORRADE_VERIFY(app._currentCursor == Application::Cursor::Hand);

/* Change to a cursor that is unknown -> fallback to an arrow */
ImGui::SetMouseCursor(ImGuiMouseCursor_COUNT);
c.updateApplicationCursor(app);
CORRADE_VERIFY(app.currentCursor == Application::Cursor::Arrow);
CORRADE_VERIFY(app._currentCursor == Application::Cursor::Arrow);

/* Change to a cursor that is conditional but present in this app */
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeAll);
c.updateApplicationCursor(app);
CORRADE_VERIFY(app.currentCursor == Application::Cursor::ResizeAll);
CORRADE_VERIFY(app._currentCursor == Application::Cursor::ResizeAll);

/* Change to a cursor that is conditional and not present -> fallback to
an arrow */
ImGui::SetMouseCursor(ImGuiMouseCursor_ResizeNESW);
c.updateApplicationCursor(app);
CORRADE_VERIFY(app.currentCursor == Application::Cursor::Arrow);
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, 10);
io.WantSetMousePos = true;
c.updateApplicationCursor(app);
CORRADE_VERIFY(app._mousePos == Vector2i(20, 20));

/* Change to imgui mouse pos without marking it as changed */
io.MousePos = ImVec2(50, 50);
io.WantSetMousePos = false;
c.updateApplicationCursor(app);
CORRADE_VERIFY(app._mousePos == Vector2i(20, 20));

/* Mark mouse pos changed */
io.WantSetMousePos = true;
c.updateApplicationCursor(app);
CORRADE_VERIFY(app._mousePos == Vector2i(100, 100));

}

void ContextGLTest::multipleContexts() {
Expand Down