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

Qt and Dear ImGui Direct3D Custom Widget Child/Parent Issue #2281

Closed
giladreich opened this issue Jan 15, 2019 · 9 comments
Closed

Qt and Dear ImGui Direct3D Custom Widget Child/Parent Issue #2281

giladreich opened this issue Jan 15, 2019 · 9 comments
Labels

Comments

@giladreich
Copy link
Contributor

Hi everyone :)

I've been trying to integrate ImGui into one of my projects using Qt and I'm having troubles to use it in a qt widget.

Basically I have a MainWindow in Qt which promotes the custom widget that the implementation can be found here:
https://github.com/giladreich/QtDirect3D/tree/master/src/QDirect3D9ImGuiWidget

And I promote that custom widget as the centeral widget.
In terms of rendering everything works great, but for some reason passing the messages to the ImGui proc doesn't work correctly. The ImGui widgets remains unresponsive while the rendering window is fully responsive.

I've looked into the part in ImGui code where ImGui::UpdateManualResize:
https://github.com/ocornut/imgui/blob/master/imgui.cpp#L4671

And this code never gets executed even though I do pass the event chain into the ImGui as you can see in the project sample that I added into GitHub:
https://github.com/giladreich/QtDirect3D/blob/master/src/QDirect3D9ImGuiWidget/QDirect3D9Widget.cpp#L221

I've spent some time on this trying to understand why it happens and I got a feeling that it has something to do with the way Qt handles the win32 api event chain and passing forward the messages that somehow conflicts with the ImGui ones.

There is also a ticket in Qt about KEYS messages that I already found a workaround for it:
https://bugreports.qt.io/browse/QTBUG-42183

Can anyone help me with this please? I would really appreciate this!
I hope I supplied all the necessary information to debug this, but if not, please do not hesitate to ask me!

sky_imgui

Version/Branch of Dear ImGui:

Version: 1.67
Branch: Release

https://github.com/giladreich/QtDirect3D/tree/master/src/QDirect3D9ImGuiWidget
Compiler: msvc141
Operating System: Windows 10
Qt Version: 5.12 msvc141 x32

@giladreich
Copy link
Contributor Author

I also wanted to mention, that this only happens when I use the HWND of the widget. But if I move all that code from the widget to be in the MainWindow(basically getting the HWND of the main window), it would work perfectly fine and I could fully interact with the ImGui widgets. But this is a problem, as if I give the direct3d device the handle of the MainWindow, it will draw everything on top of all Qt widgets, which is why I created the QDirect3DWidget so all the scene is encapsulated in one place and I can also use the Qt widgets at the same time.
I have a good feeling that it might have to do somewhere in the ImGui code that it retrieves the main handle while ignoring the fact that we gave it an actual handle(to a widget), i.e:
ImGui_ImplWin32_Init(m_hWnd);
From the examples.
As the hover events will be fully ignored and not work in the ImGui widgets, since it's not part of the messages chain, i.e:

	if (ImGui_ImplWin32_WndProcHandler(hWnd, msg, wParam, lParam))
	{
		return TRUE;
	}

Even if I remove that line in the ImGui examples the hover events will work and the widgets will be showed highlighted, but of course won't be able to drag and interact as this is just for debugging purposes.

@ocornut
Copy link
Owner

ocornut commented Jan 15, 2019

I haven't looked in details (and unlikely to be since I don't use Qt), but it is possible the same issue as discussed in #2232, #2156, #2087

Also see #1910.

@giladreich
Copy link
Contributor Author

giladreich commented Jan 15, 2019

Oh wow...I've spent some time on this and that's it!

static void ImGui_ImplWin32_UpdateMousePos()
{
    ImGuiIO& io = ImGui::GetIO();

    // Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
    if (io.WantSetMousePos)
    {
        POINT pos = { (int)io.MousePos.x, (int)io.MousePos.y };
        ::ClientToScreen(g_hWnd, &pos);
        ::SetCursorPos(pos.x, pos.y);
    }

    // Set mouse position
    io.MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
    POINT pos;
    HWND hActive = ::GetActiveWindow();
    if ((hActive == g_hWnd || ::IsChild(hActive , g_hWnd)) && ::GetCursorPos(&pos))
        if (::ScreenToClient(g_hWnd, &pos))
            io.MousePos = ImVec2((float)pos.x, (float)pos.y);
}

@ocornut You made my day! Thanks a lot for the references! I also wonder at the same time why isn't it merged into the release?

@ocornut
Copy link
Owner

ocornut commented Jan 15, 2019 via email

@giladreich
Copy link
Contributor Author

Oh well...I'm extremely happy now that I can use and get on with ImGui in my projects thanks to you! and also looking forward to see the upcoming future of it. So big thanks for everything again! :)

@ocornut
Copy link
Owner

ocornut commented Jan 15, 2019

Applied this change to master now.
Good luck!

@ocornut ocornut closed this as completed Jan 15, 2019
@giladreich
Copy link
Contributor Author

giladreich commented Jan 17, 2019

Hey again @ocornut,
Sorry to bring it once again, but I just wanted to include imgui as submodule in my project to use the master branch and unfortunately the commit 133f112 didn't fix it for me, i.e, that check:

if (::GetForegroundWindow() == g_hWnd)

I think what you really want to check in this case is something similar to this:

static bool g_isWindowActive = false;

BOOL CALLBACK EnumChildProc(_In_ HWND hWnd, _In_ LPARAM lParam)
{
    if (g_hWnd == hWnd)
    {
        g_isWindowActive = true;
        return FALSE;
    }

    g_isWindowActive = false;
    return TRUE; // Return true will continue the enumeration of all child handles.
}

static bool IsGivenWindowActive()
{
    HWND const hParent = ::GetActiveWindow();
    if (hParent == g_hWnd)
    {
        g_isWindowActive = true;
        return true;
    }

    EnumChildWindows(hParent, EnumChildProc, NULL);
    return g_isWindowActive;
}

Then we can use it in our problematic check like so:

if (IsGivenWindowActive() && ::GetCursorPos(&pos))

And I don't think there is a big concern of performance here and normally you wouldn't have many handles(HWND) for a render window. But in a situation where you have a parent window and we give it a child window handle to render to (for example in my case where I render in Qt), then this should do a proper job.

Let me know what you think :)

EDIT:
I think IsChild actually does the same thing behind the scene, but this can be as alternative solution for us.
https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-ischild

@ocornut ocornut reopened this Jan 17, 2019
@giladreich giladreich changed the title Qt and Dear ImGui Direct3D Custom Widget Win32 Messages Issue Qt and Dear ImGui Direct3D Custom Widget Child/Parent Issue Jan 17, 2019
@ocornut
Copy link
Owner

ocornut commented Jan 17, 2019

I pushed a change using ::IsChild() now. Let me know if it works for you!

@ocornut ocornut closed this as completed Jan 17, 2019
@giladreich
Copy link
Contributor Author

Perfect! Thank you once again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants