2020-10-12 17:34:22 +02:00
// dear imgui: Platform Backend for Windows (standard windows API for 32 and 64 bits applications)
2018-02-21 23:05:17 +01:00
// This needs to be used along with a Renderer (e.g. DirectX11, OpenGL3, Vulkan..)
2018-06-11 12:33:51 +02:00
// Implemented features:
2020-02-17 10:11:26 +01:00
// [X] Platform: Clipboard support (for Win32 this is actually part of core dear imgui)
2018-06-11 12:33:51 +02:00
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
2018-06-30 14:33:45 +02:00
// [X] Platform: Keyboard arrays indexed using VK_* Virtual Key Codes, e.g. ImGui::IsKeyPressed(VK_SPACE).
2019-01-15 21:17:48 +01:00
// [X] Platform: Gamepad support. Enabled with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
2018-06-12 16:24:24 +02:00
// [X] Platform: Multi-viewport support (multiple windows). Enable with 'io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable'.
2018-06-11 12:33:51 +02:00
2020-10-14 12:22:53 +02:00
// You can copy and use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// If you are new to Dear ImGui, read documentation from the docs/ folder + read the top of imgui.cpp.
// Read online: https://github.com/ocornut/imgui/tree/master/docs
2018-02-16 23:04:17 +01:00
# include "imgui.h"
# include "imgui_impl_win32.h"
2018-08-09 17:32:31 +02:00
# ifndef WIN32_LEAN_AND_MEAN
2018-02-16 23:04:17 +01:00
# define WIN32_LEAN_AND_MEAN
2018-08-09 17:32:31 +02:00
# endif
2018-02-16 23:04:17 +01:00
# include <windows.h>
2018-02-27 23:26:51 +01:00
# include <tchar.h>
2020-01-14 14:58:32 +01:00
// Using XInput library for gamepad (with recent Windows SDK this may leads to executables which won't run on Windows 7)
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
# include <XInput.h>
# else
# define IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT
# endif
# if defined(_MSC_VER) && !defined(IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT)
# pragma comment(lib, "xinput")
//#pragma comment(lib, "Xinput9_1_0")
# endif
2018-02-20 16:18:02 +01:00
// CHANGELOG
2018-04-26 16:07:54 +02:00
// (minor and older changes stripped away, please see git history for details)
2020-01-10 14:38:09 +01:00
// 2020-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
2020-03-03 17:45:06 +01:00
// 2020-03-03: Inputs: Calling AddInputCharacterUTF16() to support surrogate pairs leading to codepoint >= 0x10000 (for more complete CJK inputs)
2020-02-17 11:11:08 +01:00
// 2020-02-17: Added ImGui_ImplWin32_EnableDpiAwareness(), ImGui_ImplWin32_GetDpiScaleForHwnd(), ImGui_ImplWin32_GetDpiScaleForMonitor() helper functions.
2020-01-14 14:58:32 +01:00
// 2020-01-14: Inputs: Added support for #define IMGUI_IMPL_WIN32_DISABLE_GAMEPAD/IMGUI_IMPL_WIN32_DISABLE_LINKING_XINPUT.
2019-12-05 15:43:05 +01:00
// 2019-12-05: Inputs: Added support for ImGuiMouseCursor_NotAllowed mouse cursor.
2019-05-11 10:33:56 +02:00
// 2019-05-11: Inputs: Don't filter value from WM_CHAR before calling AddInputCharacter().
2019-01-17 16:55:23 +01:00
// 2019-01-17: Misc: Using GetForegroundWindow()+IsChild() instead of GetActiveWindow() to be compatible with windows created in a different thread or parent.
// 2019-01-17: Inputs: Added support for mouse buttons 4 and 5 via WM_XBUTTON* messages.
2019-01-15 21:17:48 +01:00
// 2019-01-15: Inputs: Added support for XInput gamepads (if ImGuiConfigFlags_NavEnableGamepad is set by user application).
2018-11-30 18:18:15 +01:00
// 2018-11-30: Misc: Setting up io.BackendPlatformName so it can be displayed in the About Window.
2018-06-29 16:30:41 +02:00
// 2018-06-29: Inputs: Added support for the ImGuiMouseCursor_Hand cursor.
2018-06-11 17:34:56 +02:00
// 2018-06-10: Inputs: Fixed handling of mouse wheel messages to support fine position messages (typically sent by track-pads).
2018-06-08 19:37:33 +02:00
// 2018-06-08: Misc: Extracted imgui_impl_win32.cpp/.h away from the old combined DX9/DX10/DX11/DX12 examples.
2018-04-06 23:34:43 +02:00
// 2018-03-20: Misc: Setup io.BackendFlags ImGuiBackendFlags_HasMouseCursors and ImGuiBackendFlags_HasSetMousePos flags + honor ImGuiConfigFlags_NoMouseCursorChange flag.
2018-02-20 16:18:02 +01:00
// 2018-02-20: Inputs: Added support for mouse cursors (ImGui::GetMouseCursor() value and WM_SETCURSOR message handling).
// 2018-02-06: Inputs: Added mapping for ImGuiKey_Space.
2018-03-20 22:14:34 +01:00
// 2018-02-06: Inputs: Honoring the io.WantSetMousePos by repositioning the mouse (when using navigation and ImGuiConfigFlags_NavMoveMouse is set).
2018-02-20 16:18:02 +01:00
// 2018-02-06: Misc: Removed call to ImGui::Shutdown() which is not available from 1.60 WIP, user needs to call CreateContext/DestroyContext themselves.
// 2018-01-20: Inputs: Added Horizontal Mouse Wheel support.
// 2018-01-08: Inputs: Added mapping for ImGuiKey_Insert.
// 2018-01-05: Inputs: Added WM_LBUTTONDBLCLK double-click handlers for window classes with the CS_DBLCLKS flag.
// 2017-10-23: Inputs: Added WM_SYSKEYDOWN / WM_SYSKEYUP handlers so e.g. the VK_MENU key can be read.
2019-01-20 17:56:17 +01:00
// 2017-10-23: Inputs: Using Win32 ::SetCapture/::GetCapture() to retrieve mouse positions outside the client area when dragging.
2018-02-20 16:18:02 +01:00
// 2016-11-12: Inputs: Only call Win32 ::SetCursor(NULL) when io.MouseDrawCursor is set.
// Win32 Data
2020-01-14 14:58:32 +01:00
static HWND g_hWnd = NULL ;
2018-02-20 16:18:02 +01:00
static INT64 g_Time = 0 ;
static INT64 g_TicksPerSecond = 0 ;
2018-06-20 11:06:29 +02:00
static ImGuiMouseCursor g_LastMouseCursor = ImGuiMouseCursor_COUNT ;
2019-01-15 21:17:48 +01:00
static bool g_HasGamepad = false ;
static bool g_WantUpdateHasGamepad = true ;
2018-04-26 16:07:54 +02:00
static bool g_WantUpdateMonitors = true ;
2018-02-16 23:04:17 +01:00
2018-02-27 23:26:51 +01:00
// Forward Declarations
static void ImGui_ImplWin32_InitPlatformInterface ( ) ;
static void ImGui_ImplWin32_ShutdownPlatformInterface ( ) ;
2018-04-26 16:07:54 +02:00
static void ImGui_ImplWin32_UpdateMonitors ( ) ;
2018-02-27 23:26:51 +01:00
2018-02-16 23:04:17 +01:00
// Functions
bool ImGui_ImplWin32_Init ( void * hwnd )
{
2020-06-30 15:31:54 +02:00
if ( ! : : QueryPerformanceFrequency ( ( LARGE_INTEGER * ) & g_TicksPerSecond ) )
2018-02-16 23:04:17 +01:00
return false ;
2020-06-30 15:31:54 +02:00
if ( ! : : QueryPerformanceCounter ( ( LARGE_INTEGER * ) & g_Time ) )
2018-02-16 23:04:17 +01:00
return false ;
2020-10-12 17:34:22 +02:00
// Setup backend capabilities flags
2018-03-20 22:14:34 +01:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
io . BackendFlags | = ImGuiBackendFlags_HasMouseCursors ; // We can honor GetMouseCursor() values (optional)
io . BackendFlags | = ImGuiBackendFlags_HasSetMousePos ; // We can honor io.WantSetMousePos requests (optional, rarely used)
io . BackendFlags | = ImGuiBackendFlags_PlatformHasViewports ; // We can create multi-viewports on the Platform side (optional)
io . BackendFlags | = ImGuiBackendFlags_HasMouseHoveredViewport ; // We can set io.MouseHoveredViewport correctly (optional, not easy)
2018-11-30 18:18:15 +01:00
io . BackendPlatformName = " imgui_impl_win32 " ;
2018-03-20 22:14:34 +01:00
// Our mouse update function expect PlatformHandle to be filled for the main viewport
2018-02-16 23:04:17 +01:00
g_hWnd = ( HWND ) hwnd ;
2018-03-20 22:14:34 +01:00
ImGuiViewport * main_viewport = ImGui : : GetMainViewport ( ) ;
2019-06-18 23:35:48 +02:00
main_viewport - > PlatformHandle = main_viewport - > PlatformHandleRaw = ( void * ) g_hWnd ;
2018-04-10 19:21:52 +02:00
if ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable )
2018-03-20 22:14:34 +01:00
ImGui_ImplWin32_InitPlatformInterface ( ) ;
2018-02-16 23:04:17 +01:00
2018-04-18 19:06:49 +02:00
// Keyboard mapping. ImGui will use those indices to peek into the io.KeysDown[] array that we will update during the application lifetime.
2018-03-20 22:14:34 +01:00
io . KeyMap [ ImGuiKey_Tab ] = VK_TAB ;
2018-02-16 23:04:17 +01:00
io . KeyMap [ ImGuiKey_LeftArrow ] = VK_LEFT ;
io . KeyMap [ ImGuiKey_RightArrow ] = VK_RIGHT ;
io . KeyMap [ ImGuiKey_UpArrow ] = VK_UP ;
io . KeyMap [ ImGuiKey_DownArrow ] = VK_DOWN ;
io . KeyMap [ ImGuiKey_PageUp ] = VK_PRIOR ;
io . KeyMap [ ImGuiKey_PageDown ] = VK_NEXT ;
io . KeyMap [ ImGuiKey_Home ] = VK_HOME ;
io . KeyMap [ ImGuiKey_End ] = VK_END ;
io . KeyMap [ ImGuiKey_Insert ] = VK_INSERT ;
io . KeyMap [ ImGuiKey_Delete ] = VK_DELETE ;
io . KeyMap [ ImGuiKey_Backspace ] = VK_BACK ;
io . KeyMap [ ImGuiKey_Space ] = VK_SPACE ;
io . KeyMap [ ImGuiKey_Enter ] = VK_RETURN ;
io . KeyMap [ ImGuiKey_Escape ] = VK_ESCAPE ;
2019-07-22 03:39:50 +02:00
io . KeyMap [ ImGuiKey_KeyPadEnter ] = VK_RETURN ;
2018-02-16 23:04:17 +01:00
io . KeyMap [ ImGuiKey_A ] = ' A ' ;
io . KeyMap [ ImGuiKey_C ] = ' C ' ;
io . KeyMap [ ImGuiKey_V ] = ' V ' ;
io . KeyMap [ ImGuiKey_X ] = ' X ' ;
io . KeyMap [ ImGuiKey_Y ] = ' Y ' ;
io . KeyMap [ ImGuiKey_Z ] = ' Z ' ;
2018-02-27 23:26:51 +01:00
return true ;
2018-02-16 23:04:17 +01:00
}
void ImGui_ImplWin32_Shutdown ( )
{
2018-02-27 23:26:51 +01:00
ImGui_ImplWin32_ShutdownPlatformInterface ( ) ;
2018-02-16 23:04:17 +01:00
g_hWnd = ( HWND ) 0 ;
}
2018-03-20 22:14:34 +01:00
static bool ImGui_ImplWin32_UpdateMouseCursor ( )
2018-02-20 16:18:02 +01:00
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2018-04-06 23:34:43 +02:00
if ( io . ConfigFlags & ImGuiConfigFlags_NoMouseCursorChange )
2018-03-20 22:14:34 +01:00
return false ;
2018-05-11 16:41:32 +02:00
ImGuiMouseCursor imgui_cursor = ImGui : : GetMouseCursor ( ) ;
if ( imgui_cursor = = ImGuiMouseCursor_None | | io . MouseDrawCursor )
2018-02-20 16:18:02 +01:00
{
// Hide OS mouse cursor if imgui is drawing it or if it wants no cursor
: : SetCursor ( NULL ) ;
}
else
{
2018-05-11 16:41:32 +02:00
// Show OS mouse cursor
2018-02-20 16:18:02 +01:00
LPTSTR win32_cursor = IDC_ARROW ;
switch ( imgui_cursor )
{
case ImGuiMouseCursor_Arrow : win32_cursor = IDC_ARROW ; break ;
case ImGuiMouseCursor_TextInput : win32_cursor = IDC_IBEAM ; break ;
case ImGuiMouseCursor_ResizeAll : win32_cursor = IDC_SIZEALL ; break ;
case ImGuiMouseCursor_ResizeEW : win32_cursor = IDC_SIZEWE ; break ;
case ImGuiMouseCursor_ResizeNS : win32_cursor = IDC_SIZENS ; break ;
case ImGuiMouseCursor_ResizeNESW : win32_cursor = IDC_SIZENESW ; break ;
case ImGuiMouseCursor_ResizeNWSE : win32_cursor = IDC_SIZENWSE ; break ;
2018-06-29 12:16:17 +02:00
case ImGuiMouseCursor_Hand : win32_cursor = IDC_HAND ; break ;
2019-12-02 09:52:06 +01:00
case ImGuiMouseCursor_NotAllowed : win32_cursor = IDC_NO ; break ;
2018-02-20 16:18:02 +01:00
}
: : SetCursor ( : : LoadCursor ( NULL , win32_cursor ) ) ;
}
2018-03-20 22:14:34 +01:00
return true ;
2018-02-20 16:18:02 +01:00
}
2018-12-06 16:30:10 +01:00
// This code supports multi-viewports (multiple OS Windows mapped into different Dear ImGui viewports)
// Because of that, it is a little more complicated than your typical single-viewport binding code!
2018-02-27 23:26:51 +01:00
static void ImGui_ImplWin32_UpdateMousePos ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2018-05-11 14:05:40 +02:00
// Set OS mouse position if requested (rarely used, only when ImGuiConfigFlags_NavEnableSetMousePos is enabled by user)
2018-12-06 16:30:10 +01:00
// (When multi-viewports are enabled, all imgui positions are same as OS positions)
2018-05-11 14:05:40 +02:00
if ( io . WantSetMousePos )
{
POINT pos = { ( int ) io . MousePos . x , ( int ) io . MousePos . y } ;
if ( ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable ) = = 0 )
: : ClientToScreen ( g_hWnd , & pos ) ;
: : SetCursorPos ( pos . x , pos . y ) ;
}
2018-02-27 23:26:51 +01:00
io . MousePos = ImVec2 ( - FLT_MAX , - FLT_MAX ) ;
io . MouseHoveredViewport = 0 ;
2018-12-06 16:30:10 +01:00
// Set imgui mouse position
POINT mouse_screen_pos ;
if ( ! : : GetCursorPos ( & mouse_screen_pos ) )
2018-02-27 23:26:51 +01:00
return ;
2019-01-15 21:22:21 +01:00
if ( HWND focused_hwnd = : : GetForegroundWindow ( ) )
2018-12-06 16:30:10 +01:00
{
2019-01-17 13:59:23 +01:00
if ( : : IsChild ( focused_hwnd , g_hWnd ) )
focused_hwnd = g_hWnd ;
2018-12-06 16:30:10 +01:00
if ( io . ConfigFlags & ImGuiConfigFlags_ViewportsEnable )
{
// Multi-viewport mode: mouse position in OS absolute coordinates (io.MousePos is (0,0) when the mouse is on the upper-left of the primary monitor)
// This is the position you can get with GetCursorPos(). In theory adding viewport->Pos is also the reverse operation of doing ScreenToClient().
if ( ImGui : : FindViewportByPlatformHandle ( ( void * ) focused_hwnd ) ! = NULL )
io . MousePos = ImVec2 ( ( float ) mouse_screen_pos . x , ( float ) mouse_screen_pos . y ) ;
}
else
2018-02-27 23:26:51 +01:00
{
2018-12-06 16:30:10 +01:00
// Single viewport mode: mouse position in client window coordinates (io.MousePos is (0,0) when the mouse is on the upper-left corner of the app window.)
// This is the position you can get with GetCursorPos() + ScreenToClient() or from WM_MOUSEMOVE.
if ( focused_hwnd = = g_hWnd )
{
POINT mouse_client_pos = mouse_screen_pos ;
: : ScreenToClient ( focused_hwnd , & mouse_client_pos ) ;
io . MousePos = ImVec2 ( ( float ) mouse_client_pos . x , ( float ) mouse_client_pos . y ) ;
}
2018-02-27 23:26:51 +01:00
}
2018-12-06 16:30:10 +01:00
}
2018-05-11 14:05:40 +02:00
2018-12-06 16:30:10 +01:00
// (Optional) When using multiple viewports: set io.MouseHoveredViewport to the viewport the OS mouse cursor is hovering.
// Important: this information is not easy to provide and many high-level windowing library won't be able to provide it correctly, because
// - This is _ignoring_ viewports with the ImGuiViewportFlags_NoInputs flag (pass-through windows).
// - This is _regardless_ of whether another viewport is focused or being dragged from.
2020-10-14 14:43:45 +02:00
// If ImGuiBackendFlags_HasMouseHoveredViewport is not set by the backend, imgui will ignore this field and infer the information by relying on the
2019-01-02 18:22:31 +01:00
// rectangles and last focused time of every viewports it knows about. It will be unaware of foreign windows that may be sitting between or over your windows.
2018-12-06 16:30:10 +01:00
if ( HWND hovered_hwnd = : : WindowFromPoint ( mouse_screen_pos ) )
2018-05-11 14:05:40 +02:00
if ( ImGuiViewport * viewport = ImGui : : FindViewportByPlatformHandle ( ( void * ) hovered_hwnd ) )
2019-01-02 18:22:31 +01:00
if ( ( viewport - > Flags & ImGuiViewportFlags_NoInputs ) = = 0 ) // FIXME: We still get our NoInputs window with WM_NCHITTEST/HTTRANSPARENT code when decorated?
io . MouseHoveredViewport = viewport - > ID ;
2018-02-27 23:26:51 +01:00
}
2019-01-15 21:17:48 +01:00
// Gamepad navigation mapping
2019-02-14 18:55:08 +01:00
static void ImGui_ImplWin32_UpdateGamepads ( )
2019-01-15 21:17:48 +01:00
{
2020-01-14 14:58:32 +01:00
# ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2019-01-15 21:17:48 +01:00
ImGuiIO & io = ImGui : : GetIO ( ) ;
memset ( io . NavInputs , 0 , sizeof ( io . NavInputs ) ) ;
if ( ( io . ConfigFlags & ImGuiConfigFlags_NavEnableGamepad ) = = 0 )
return ;
// Calling XInputGetState() every frame on disconnected gamepads is unfortunately too slow.
// Instead we refresh gamepad availability by calling XInputGetCapabilities() _only_ after receiving WM_DEVICECHANGE.
if ( g_WantUpdateHasGamepad )
{
XINPUT_CAPABILITIES caps ;
g_HasGamepad = ( XInputGetCapabilities ( 0 , XINPUT_FLAG_GAMEPAD , & caps ) = = ERROR_SUCCESS ) ;
g_WantUpdateHasGamepad = false ;
}
XINPUT_STATE xinput_state ;
io . BackendFlags & = ~ ImGuiBackendFlags_HasGamepad ;
if ( g_HasGamepad & & XInputGetState ( 0 , & xinput_state ) = = ERROR_SUCCESS )
{
const XINPUT_GAMEPAD & gamepad = xinput_state . Gamepad ;
io . BackendFlags | = ImGuiBackendFlags_HasGamepad ;
# define MAP_BUTTON(NAV_NO, BUTTON_ENUM) { io.NavInputs[NAV_NO] = (gamepad.wButtons & BUTTON_ENUM) ? 1.0f : 0.0f; }
# define MAP_ANALOG(NAV_NO, VALUE, V0, V1) { float vn = (float)(VALUE - V0) / (float)(V1 - V0); if (vn > 1.0f) vn = 1.0f; if (vn > 0.0f && io.NavInputs[NAV_NO] < vn) io.NavInputs[NAV_NO] = vn; }
MAP_BUTTON ( ImGuiNavInput_Activate , XINPUT_GAMEPAD_A ) ; // Cross / A
MAP_BUTTON ( ImGuiNavInput_Cancel , XINPUT_GAMEPAD_B ) ; // Circle / B
MAP_BUTTON ( ImGuiNavInput_Menu , XINPUT_GAMEPAD_X ) ; // Square / X
MAP_BUTTON ( ImGuiNavInput_Input , XINPUT_GAMEPAD_Y ) ; // Triangle / Y
MAP_BUTTON ( ImGuiNavInput_DpadLeft , XINPUT_GAMEPAD_DPAD_LEFT ) ; // D-Pad Left
MAP_BUTTON ( ImGuiNavInput_DpadRight , XINPUT_GAMEPAD_DPAD_RIGHT ) ; // D-Pad Right
MAP_BUTTON ( ImGuiNavInput_DpadUp , XINPUT_GAMEPAD_DPAD_UP ) ; // D-Pad Up
MAP_BUTTON ( ImGuiNavInput_DpadDown , XINPUT_GAMEPAD_DPAD_DOWN ) ; // D-Pad Down
MAP_BUTTON ( ImGuiNavInput_FocusPrev , XINPUT_GAMEPAD_LEFT_SHOULDER ) ; // L1 / LB
MAP_BUTTON ( ImGuiNavInput_FocusNext , XINPUT_GAMEPAD_RIGHT_SHOULDER ) ; // R1 / RB
MAP_BUTTON ( ImGuiNavInput_TweakSlow , XINPUT_GAMEPAD_LEFT_SHOULDER ) ; // L1 / LB
MAP_BUTTON ( ImGuiNavInput_TweakFast , XINPUT_GAMEPAD_RIGHT_SHOULDER ) ; // R1 / RB
MAP_ANALOG ( ImGuiNavInput_LStickLeft , gamepad . sThumbLX , - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , - 32768 ) ;
MAP_ANALOG ( ImGuiNavInput_LStickRight , gamepad . sThumbLX , + XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , + 32767 ) ;
MAP_ANALOG ( ImGuiNavInput_LStickUp , gamepad . sThumbLY , + XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , + 32767 ) ;
MAP_ANALOG ( ImGuiNavInput_LStickDown , gamepad . sThumbLY , - XINPUT_GAMEPAD_LEFT_THUMB_DEADZONE , - 32767 ) ;
# undef MAP_BUTTON
# undef MAP_ANALOG
}
2020-01-14 14:58:32 +01:00
# endif // #ifndef IMGUI_IMPL_WIN32_DISABLE_GAMEPAD
2019-01-15 21:17:48 +01:00
}
2020-02-09 17:31:18 +01:00
static BOOL CALLBACK ImGui_ImplWin32_UpdateMonitors_EnumFunc ( HMONITOR monitor , HDC , LPRECT , LPARAM )
{
MONITORINFO info = { 0 } ;
info . cbSize = sizeof ( MONITORINFO ) ;
if ( ! : : GetMonitorInfo ( monitor , & info ) )
return TRUE ;
ImGuiPlatformMonitor imgui_monitor ;
imgui_monitor . MainPos = ImVec2 ( ( float ) info . rcMonitor . left , ( float ) info . rcMonitor . top ) ;
imgui_monitor . MainSize = ImVec2 ( ( float ) ( info . rcMonitor . right - info . rcMonitor . left ) , ( float ) ( info . rcMonitor . bottom - info . rcMonitor . top ) ) ;
imgui_monitor . WorkPos = ImVec2 ( ( float ) info . rcWork . left , ( float ) info . rcWork . top ) ;
imgui_monitor . WorkSize = ImVec2 ( ( float ) ( info . rcWork . right - info . rcWork . left ) , ( float ) ( info . rcWork . bottom - info . rcWork . top ) ) ;
imgui_monitor . DpiScale = ImGui_ImplWin32_GetDpiScaleForMonitor ( monitor ) ;
ImGuiPlatformIO & io = ImGui : : GetPlatformIO ( ) ;
if ( info . dwFlags & MONITORINFOF_PRIMARY )
io . Monitors . push_front ( imgui_monitor ) ;
else
io . Monitors . push_back ( imgui_monitor ) ;
return TRUE ;
}
static void ImGui_ImplWin32_UpdateMonitors ( )
{
ImGui : : GetPlatformIO ( ) . Monitors . resize ( 0 ) ;
: : EnumDisplayMonitors ( NULL , NULL , ImGui_ImplWin32_UpdateMonitors_EnumFunc , NULL ) ;
g_WantUpdateMonitors = false ;
}
2018-02-16 23:04:17 +01:00
void ImGui_ImplWin32_NewFrame ( )
{
ImGuiIO & io = ImGui : : GetIO ( ) ;
2020-10-12 17:34:22 +02:00
IM_ASSERT ( io . Fonts - > IsBuilt ( ) & & " Font atlas not built! It is generally built by the renderer backend. Missing call to renderer _NewFrame() function? e.g. ImGui_ImplOpenGL3_NewFrame(). " ) ;
2018-02-16 23:04:17 +01:00
// Setup display size (every frame to accommodate for window resizing)
RECT rect ;
2018-02-18 21:23:11 +01:00
: : GetClientRect ( g_hWnd , & rect ) ;
2018-02-16 23:04:17 +01:00
io . DisplaySize = ImVec2 ( ( float ) ( rect . right - rect . left ) , ( float ) ( rect . bottom - rect . top ) ) ;
2018-04-26 16:07:54 +02:00
if ( g_WantUpdateMonitors )
ImGui_ImplWin32_UpdateMonitors ( ) ;
2018-02-16 23:04:17 +01:00
// Setup time step
INT64 current_time ;
2020-06-30 15:31:54 +02:00
: : QueryPerformanceCounter ( ( LARGE_INTEGER * ) & current_time ) ;
2018-02-16 23:04:17 +01:00
io . DeltaTime = ( float ) ( current_time - g_Time ) / g_TicksPerSecond ;
g_Time = current_time ;
// Read keyboard modifiers inputs
2018-02-18 21:23:11 +01:00
io . KeyCtrl = ( : : GetKeyState ( VK_CONTROL ) & 0x8000 ) ! = 0 ;
io . KeyShift = ( : : GetKeyState ( VK_SHIFT ) & 0x8000 ) ! = 0 ;
io . KeyAlt = ( : : GetKeyState ( VK_MENU ) & 0x8000 ) ! = 0 ;
2018-02-16 23:04:17 +01:00
io . KeySuper = false ;
2018-05-11 14:05:40 +02:00
// io.KeysDown[], io.MousePos, io.MouseDown[], io.MouseWheel: filled by the WndProc handler below.
2018-02-16 23:04:17 +01:00
2018-05-11 14:05:40 +02:00
// Update OS mouse position
ImGui_ImplWin32_UpdateMousePos ( ) ;
2018-02-16 23:04:17 +01:00
2018-02-20 16:18:02 +01:00
// Update OS mouse cursor with the cursor requested by imgui
ImGuiMouseCursor mouse_cursor = io . MouseDrawCursor ? ImGuiMouseCursor_None : ImGui : : GetMouseCursor ( ) ;
if ( g_LastMouseCursor ! = mouse_cursor )
{
g_LastMouseCursor = mouse_cursor ;
ImGui_ImplWin32_UpdateMouseCursor ( ) ;
}
2019-01-15 21:17:48 +01:00
2019-04-23 12:26:14 +02:00
// Update game controllers (if enabled and available)
2019-02-14 18:55:08 +01:00
ImGui_ImplWin32_UpdateGamepads ( ) ;
2018-02-16 23:04:17 +01:00
}
2018-04-04 19:39:42 +02:00
// Allow compilation with old Windows SDK. MinGW doesn't have default _WIN32_WINNT/WINVER versions.
# ifndef WM_MOUSEHWHEEL
# define WM_MOUSEHWHEEL 0x020E
# endif
2019-01-15 21:17:48 +01:00
# ifndef DBT_DEVNODES_CHANGED
# define DBT_DEVNODES_CHANGED 0x0007
# endif
2018-04-04 19:39:42 +02:00
2020-02-17 10:11:26 +01:00
// Win32 message handler (process Win32 mouse/keyboard inputs, etc.)
// Call from your application's message handler.
2020-10-12 17:34:22 +02:00
// When implementing your own backend, you can read the io.WantCaptureMouse, io.WantCaptureKeyboard flags to tell if Dear ImGui wants to use your inputs.
2018-02-16 23:04:17 +01:00
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application.
2020-02-17 10:11:26 +01:00
// Generally you may always pass all inputs to Dear ImGui, and hide them from your application based on those two flags.
2019-03-09 10:10:17 +01:00
// PS: In this Win32 handler, we use the capture API (GetCapture/SetCapture/ReleaseCapture) to be able to read mouse coordinates when dragging mouse outside of our window bounds.
2018-02-16 23:04:17 +01:00
// PS: We treat DBLCLK messages as regular mouse down messages, so this code will work on windows classes that have the CS_DBLCLKS flag set. Our own example app code doesn't set this flag.
2020-02-17 10:11:26 +01:00
#if 0
// Copy this line into your .cpp file to forward declare the function.
extern IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler ( HWND hWnd , UINT msg , WPARAM wParam , LPARAM lParam ) ;
# endif
2018-06-21 12:04:00 +02:00
IMGUI_IMPL_API LRESULT ImGui_ImplWin32_WndProcHandler ( HWND hwnd , UINT msg , WPARAM wParam , LPARAM lParam )
2018-02-16 23:04:17 +01:00
{
if ( ImGui : : GetCurrentContext ( ) = = NULL )
return 0 ;
ImGuiIO & io = ImGui : : GetIO ( ) ;
switch ( msg )
{
case WM_LBUTTONDOWN : case WM_LBUTTONDBLCLK :
case WM_RBUTTONDOWN : case WM_RBUTTONDBLCLK :
case WM_MBUTTONDOWN : case WM_MBUTTONDBLCLK :
2019-01-17 16:55:23 +01:00
case WM_XBUTTONDOWN : case WM_XBUTTONDBLCLK :
2018-02-16 23:04:17 +01:00
{
int button = 0 ;
2019-01-17 16:55:23 +01:00
if ( msg = = WM_LBUTTONDOWN | | msg = = WM_LBUTTONDBLCLK ) { button = 0 ; }
if ( msg = = WM_RBUTTONDOWN | | msg = = WM_RBUTTONDBLCLK ) { button = 1 ; }
if ( msg = = WM_MBUTTONDOWN | | msg = = WM_MBUTTONDBLCLK ) { button = 2 ; }
if ( msg = = WM_XBUTTONDOWN | | msg = = WM_XBUTTONDBLCLK ) { button = ( GET_XBUTTON_WPARAM ( wParam ) = = XBUTTON1 ) ? 3 : 4 ; }
2018-02-16 23:04:17 +01:00
if ( ! ImGui : : IsAnyMouseDown ( ) & & : : GetCapture ( ) = = NULL )
: : SetCapture ( hwnd ) ;
io . MouseDown [ button ] = true ;
return 0 ;
}
case WM_LBUTTONUP :
case WM_RBUTTONUP :
case WM_MBUTTONUP :
2019-01-17 16:55:23 +01:00
case WM_XBUTTONUP :
2018-02-16 23:04:17 +01:00
{
int button = 0 ;
2019-01-17 16:55:23 +01:00
if ( msg = = WM_LBUTTONUP ) { button = 0 ; }
if ( msg = = WM_RBUTTONUP ) { button = 1 ; }
if ( msg = = WM_MBUTTONUP ) { button = 2 ; }
if ( msg = = WM_XBUTTONUP ) { button = ( GET_XBUTTON_WPARAM ( wParam ) = = XBUTTON1 ) ? 3 : 4 ; }
2018-02-16 23:04:17 +01:00
io . MouseDown [ button ] = false ;
if ( ! ImGui : : IsAnyMouseDown ( ) & & : : GetCapture ( ) = = hwnd )
: : ReleaseCapture ( ) ;
return 0 ;
}
case WM_MOUSEWHEEL :
2018-06-11 17:34:56 +02:00
io . MouseWheel + = ( float ) GET_WHEEL_DELTA_WPARAM ( wParam ) / ( float ) WHEEL_DELTA ;
2018-02-16 23:04:17 +01:00
return 0 ;
case WM_MOUSEHWHEEL :
2018-06-11 17:34:56 +02:00
io . MouseWheelH + = ( float ) GET_WHEEL_DELTA_WPARAM ( wParam ) / ( float ) WHEEL_DELTA ;
2018-02-16 23:04:17 +01:00
return 0 ;
case WM_KEYDOWN :
case WM_SYSKEYDOWN :
if ( wParam < 256 )
io . KeysDown [ wParam ] = 1 ;
return 0 ;
case WM_KEYUP :
case WM_SYSKEYUP :
if ( wParam < 256 )
io . KeysDown [ wParam ] = 0 ;
return 0 ;
case WM_CHAR :
// You can also use ToAscii()+GetKeyboardState() to retrieve characters.
2019-05-08 04:10:20 +02:00
if ( wParam > 0 & & wParam < 0x10000 )
io . AddInputCharacterUTF16 ( ( unsigned short ) wParam ) ;
2018-02-16 23:04:17 +01:00
return 0 ;
2018-02-20 16:18:02 +01:00
case WM_SETCURSOR :
2018-03-20 22:14:34 +01:00
if ( LOWORD ( lParam ) = = HTCLIENT & & ImGui_ImplWin32_UpdateMouseCursor ( ) )
2018-02-20 16:18:02 +01:00
return 1 ;
return 0 ;
2019-01-15 21:17:48 +01:00
case WM_DEVICECHANGE :
if ( ( UINT ) wParam = = DBT_DEVNODES_CHANGED )
g_WantUpdateHasGamepad = true ;
return 0 ;
2018-04-26 16:07:54 +02:00
case WM_DISPLAYCHANGE :
g_WantUpdateMonitors = true ;
return 0 ;
2018-02-16 23:04:17 +01:00
}
return 0 ;
2018-02-16 23:15:14 +01:00
}
2018-02-27 23:26:51 +01:00
2020-02-17 11:11:08 +01:00
//--------------------------------------------------------------------------------------------------------
// DPI-related helpers (optional)
2018-04-24 12:40:38 +02:00
//--------------------------------------------------------------------------------------------------------
2020-02-17 11:11:08 +01:00
// - Use to enable DPI awareness without having to create an application manifest.
// - Your own app may already do this via a manifest or explicit calls. This is mostly useful for our examples/ apps.
// - In theory we could call simple functions from Windows SDK such as SetProcessDPIAware(), SetProcessDpiAwareness(), etc.
// but most of the functions provided by Microsoft require Windows 8.1/10+ SDK at compile time and Windows 8/10+ at runtime,
// neither we want to require the user to have. So we dynamically select and load those functions to avoid dependencies.
2018-03-09 19:02:52 +01:00
//---------------------------------------------------------------------------------------------------------
2020-02-17 11:11:08 +01:00
// This is the scheme successfully used by GLFW (from which we borrowed some of the code) and other apps aiming to be highly portable.
// ImGui_ImplWin32_EnableDpiAwareness() is just a helper called by main.cpp, we don't call it automatically.
2020-10-12 17:34:22 +02:00
// If you are trying to implement your own backend for your own engine, you may ignore that noise.
2018-03-09 19:02:52 +01:00
//---------------------------------------------------------------------------------------------------------
2020-02-17 11:11:08 +01:00
// Implement some of the functions and types normally declared in recent Windows SDK.
# if !defined(_versionhelpers_H_INCLUDED_) && !defined(_INC_VERSIONHELPERS)
2018-03-09 19:02:52 +01:00
static BOOL IsWindowsVersionOrGreater ( WORD major , WORD minor , WORD sp )
{
2020-05-04 20:46:20 +02:00
OSVERSIONINFOEXW osvi = { sizeof ( osvi ) , major , minor , 0 , 0 , { 0 } , sp , 0 , 0 , 0 , 0 } ;
2018-03-09 19:02:52 +01:00
DWORD mask = VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR ;
2020-02-17 11:11:08 +01:00
ULONGLONG cond = : : VerSetConditionMask ( 0 , VER_MAJORVERSION , VER_GREATER_EQUAL ) ;
cond = : : VerSetConditionMask ( cond , VER_MINORVERSION , VER_GREATER_EQUAL ) ;
cond = : : VerSetConditionMask ( cond , VER_SERVICEPACKMAJOR , VER_GREATER_EQUAL ) ;
return : : VerifyVersionInfoW ( & osvi , mask , cond ) ;
2018-03-09 19:02:52 +01:00
}
# define IsWindows8Point1OrGreater() IsWindowsVersionOrGreater(HIBYTE(0x0602), LOBYTE(0x0602), 0) // _WIN32_WINNT_WINBLUE
2020-02-17 11:11:08 +01:00
# endif
2018-03-09 19:02:52 +01:00
# ifndef DPI_ENUMS_DECLARED
typedef enum { PROCESS_DPI_UNAWARE = 0 , PROCESS_SYSTEM_DPI_AWARE = 1 , PROCESS_PER_MONITOR_DPI_AWARE = 2 } PROCESS_DPI_AWARENESS ;
typedef enum { MDT_EFFECTIVE_DPI = 0 , MDT_ANGULAR_DPI = 1 , MDT_RAW_DPI = 2 , MDT_DEFAULT = MDT_EFFECTIVE_DPI } MONITOR_DPI_TYPE ;
# endif
2018-04-13 00:01:55 +02:00
# ifndef _DPI_AWARENESS_CONTEXTS_
DECLARE_HANDLE ( DPI_AWARENESS_CONTEXT ) ;
# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE (DPI_AWARENESS_CONTEXT)-3
2019-01-17 14:35:26 +01:00
# endif
# ifndef DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2
2018-04-13 00:01:55 +02:00
# define DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 (DPI_AWARENESS_CONTEXT)-4
# endif
2020-02-17 11:11:08 +01:00
typedef HRESULT ( WINAPI * PFN_SetProcessDpiAwareness ) ( PROCESS_DPI_AWARENESS ) ; // Shcore.lib + dll, Windows 8.1+
typedef HRESULT ( WINAPI * PFN_GetDpiForMonitor ) ( HMONITOR , MONITOR_DPI_TYPE , UINT * , UINT * ) ; // Shcore.lib + dll, Windows 8.1+
typedef DPI_AWARENESS_CONTEXT ( WINAPI * PFN_SetThreadDpiAwarenessContext ) ( DPI_AWARENESS_CONTEXT ) ; // User32.lib + dll, Windows 10 v1607+ (Creators Update)
2018-03-09 19:02:52 +01:00
2020-02-17 11:11:08 +01:00
// Helper function to enable DPI awareness without setting up a manifest
2018-03-09 19:02:52 +01:00
void ImGui_ImplWin32_EnableDpiAwareness ( )
{
2020-05-08 22:02:15 +02:00
// Make sure monitors will be updated with latest correct scaling
g_WantUpdateMonitors = true ;
2020-02-17 11:11:08 +01:00
// if (IsWindows10OrGreater()) // This needs a manifest to succeed. Instead we try to grab the function pointer!
2018-04-13 00:01:55 +02:00
{
static HINSTANCE user32_dll = : : LoadLibraryA ( " user32.dll " ) ; // Reference counted per-process
if ( PFN_SetThreadDpiAwarenessContext SetThreadDpiAwarenessContextFn = ( PFN_SetThreadDpiAwarenessContext ) : : GetProcAddress ( user32_dll , " SetThreadDpiAwarenessContext " ) )
{
SetThreadDpiAwarenessContextFn ( DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 ) ;
return ;
}
}
2018-03-09 19:02:52 +01:00
if ( IsWindows8Point1OrGreater ( ) )
{
static HINSTANCE shcore_dll = : : LoadLibraryA ( " shcore.dll " ) ; // Reference counted per-process
if ( PFN_SetProcessDpiAwareness SetProcessDpiAwarenessFn = ( PFN_SetProcessDpiAwareness ) : : GetProcAddress ( shcore_dll , " SetProcessDpiAwareness " ) )
2020-02-17 11:11:08 +01:00
{
2018-03-09 19:02:52 +01:00
SetProcessDpiAwarenessFn ( PROCESS_PER_MONITOR_DPI_AWARE ) ;
2020-02-17 11:11:08 +01:00
return ;
}
2018-03-09 19:02:52 +01:00
}
2020-05-04 20:46:20 +02:00
# if _WIN32_WINNT >= 0x0600
: : SetProcessDPIAware ( ) ;
# endif
2018-03-09 19:02:52 +01:00
}
2020-04-19 17:52:09 +02:00
# if defined(_MSC_VER) && !defined(NOGDI)
2020-02-17 11:11:08 +01:00
# pragma comment(lib, "gdi32") // Link with gdi32.lib for GetDeviceCaps()
2019-02-01 15:23:25 +01:00
# endif
2018-03-09 19:02:52 +01:00
float ImGui_ImplWin32_GetDpiScaleForMonitor ( void * monitor )
{
UINT xdpi = 96 , ydpi = 96 ;
2020-06-05 01:23:18 +02:00
static BOOL bIsWindows8Point1OrGreater = IsWindows8Point1OrGreater ( ) ;
if ( bIsWindows8Point1OrGreater )
2018-03-09 19:02:52 +01:00
{
static HINSTANCE shcore_dll = : : LoadLibraryA ( " shcore.dll " ) ; // Reference counted per-process
if ( PFN_GetDpiForMonitor GetDpiForMonitorFn = ( PFN_GetDpiForMonitor ) : : GetProcAddress ( shcore_dll , " GetDpiForMonitor " ) )
GetDpiForMonitorFn ( ( HMONITOR ) monitor , MDT_EFFECTIVE_DPI , & xdpi , & ydpi ) ;
}
2020-04-19 17:52:09 +02:00
# ifndef NOGDI
2018-03-09 19:02:52 +01:00
else
{
const HDC dc = : : GetDC ( NULL ) ;
xdpi = : : GetDeviceCaps ( dc , LOGPIXELSX ) ;
ydpi = : : GetDeviceCaps ( dc , LOGPIXELSY ) ;
: : ReleaseDC ( NULL , dc ) ;
}
2020-04-19 17:52:09 +02:00
# endif
2018-03-09 19:02:52 +01:00
IM_ASSERT ( xdpi = = ydpi ) ; // Please contact me if you hit this assert!
return xdpi / 96.0f ;
}
float ImGui_ImplWin32_GetDpiScaleForHwnd ( void * hwnd )
{
HMONITOR monitor = : : MonitorFromWindow ( ( HWND ) hwnd , MONITOR_DEFAULTTONEAREST ) ;
return ImGui_ImplWin32_GetDpiScaleForMonitor ( monitor ) ;
}
2020-02-17 18:33:59 +01:00
2018-04-24 12:40:38 +02:00
//--------------------------------------------------------------------------------------------------------
// IME (Input Method Editor) basic support for e.g. Asian language users
//--------------------------------------------------------------------------------------------------------
2020-03-09 14:20:59 +01:00
# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) // UWP doesn't have Win32 functions
# define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
# endif
2018-11-05 17:28:46 +01:00
# if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(__GNUC__)
2018-04-24 12:40:38 +02:00
# define HAS_WIN32_IME 1
# include <imm.h>
# ifdef _MSC_VER
# pragma comment(lib, "imm32")
# endif
static void ImGui_ImplWin32_SetImeInputPos ( ImGuiViewport * viewport , ImVec2 pos )
{
COMPOSITIONFORM cf = { CFS_FORCE_POSITION , { ( LONG ) ( pos . x - viewport - > Pos . x ) , ( LONG ) ( pos . y - viewport - > Pos . y ) } , { 0 , 0 , 0 , 0 } } ;
if ( HWND hwnd = ( HWND ) viewport - > PlatformHandle )
2018-07-09 16:24:01 +02:00
if ( HIMC himc = : : ImmGetContext ( hwnd ) )
{
: : ImmSetCompositionWindow ( himc , & cf ) ;
: : ImmReleaseContext ( hwnd , himc ) ;
}
2018-04-24 12:40:38 +02:00
}
# else
# define HAS_WIN32_IME 0
# endif
//--------------------------------------------------------------------------------------------------------
2018-04-24 17:09:50 +02:00
// MULTI-VIEWPORT / PLATFORM INTERFACE SUPPORT
2020-10-14 14:43:45 +02:00
// This is an _advanced_ and _optional_ feature, allowing the backend to create and handle multiple viewports simultaneously.
2018-04-24 17:09:50 +02:00
// If you are new to dear imgui or creating a new binding for dear imgui, it is recommended that you completely ignore this section first..
2018-04-24 12:40:38 +02:00
//--------------------------------------------------------------------------------------------------------
2018-02-27 23:26:51 +01:00
2020-01-20 19:33:46 +01:00
// Helper structure we store in the void* RenderUserData field of each ImGuiViewport to easily retrieve our backend data.
2018-03-18 22:19:02 +01:00
struct ImGuiViewportDataWin32
2018-02-27 23:26:51 +01:00
{
HWND Hwnd ;
2018-04-09 22:01:24 +02:00
bool HwndOwned ;
2018-02-27 23:26:51 +01:00
DWORD DwStyle ;
DWORD DwExStyle ;
2018-04-09 22:01:24 +02:00
ImGuiViewportDataWin32 ( ) { Hwnd = NULL ; HwndOwned = false ; DwStyle = DwExStyle = 0 ; }
2018-03-18 22:19:02 +01:00
~ ImGuiViewportDataWin32 ( ) { IM_ASSERT ( Hwnd = = NULL ) ; }
2018-02-27 23:26:51 +01:00
} ;
2019-01-02 16:06:58 +01:00
static void ImGui_ImplWin32_GetWin32StyleFromViewportFlags ( ImGuiViewportFlags flags , DWORD * out_style , DWORD * out_ex_style )
{
if ( flags & ImGuiViewportFlags_NoDecoration )
* out_style = WS_POPUP ;
else
* out_style = WS_OVERLAPPEDWINDOW ;
if ( flags & ImGuiViewportFlags_NoTaskBarIcon )
* out_ex_style = WS_EX_TOOLWINDOW ;
else
* out_ex_style = WS_EX_APPWINDOW ;
if ( flags & ImGuiViewportFlags_TopMost )
* out_ex_style | = WS_EX_TOPMOST ;
}
2018-03-18 18:44:57 +01:00
static void ImGui_ImplWin32_CreateWindow ( ImGuiViewport * viewport )
2018-02-27 23:26:51 +01:00
{
2018-03-18 22:19:02 +01:00
ImGuiViewportDataWin32 * data = IM_NEW ( ImGuiViewportDataWin32 ) ( ) ;
2018-02-27 23:26:51 +01:00
viewport - > PlatformUserData = data ;
2019-01-02 16:06:58 +01:00
// Select style and parent window
ImGui_ImplWin32_GetWin32StyleFromViewportFlags ( viewport - > Flags , & data - > DwStyle , & data - > DwExStyle ) ;
2019-01-02 19:29:33 +01:00
HWND parent_window = NULL ;
if ( viewport - > ParentViewportId ! = 0 )
if ( ImGuiViewport * parent_viewport = ImGui : : FindViewportByID ( viewport - > ParentViewportId ) )
parent_window = ( HWND ) parent_viewport - > PlatformHandle ;
2018-02-27 23:26:51 +01:00
// Create window
2018-04-20 21:29:16 +02:00
RECT rect = { ( LONG ) viewport - > Pos . x , ( LONG ) viewport - > Pos . y , ( LONG ) ( viewport - > Pos . x + viewport - > Size . x ) , ( LONG ) ( viewport - > Pos . y + viewport - > Size . y ) } ;
2018-02-27 23:26:51 +01:00
: : AdjustWindowRectEx ( & rect , data - > DwStyle , FALSE , data - > DwExStyle ) ;
2018-04-09 22:01:24 +02:00
data - > Hwnd = : : CreateWindowEx (
2019-01-02 16:06:58 +01:00
data - > DwExStyle , _T ( " ImGui Platform " ) , _T ( " Untitled " ) , data - > DwStyle , // Style, class name, window name
rect . left , rect . top , rect . right - rect . left , rect . bottom - rect . top , // Window area
parent_window , NULL , : : GetModuleHandle ( NULL ) , NULL ) ; // Parent window, Menu, Instance, Param
2018-04-09 22:01:24 +02:00
data - > HwndOwned = true ;
2018-03-15 10:54:27 +01:00
viewport - > PlatformRequestResize = false ;
2019-06-18 23:35:48 +02:00
viewport - > PlatformHandle = viewport - > PlatformHandleRaw = data - > Hwnd ;
2018-02-27 23:26:51 +01:00
}
2018-03-18 18:44:57 +01:00
static void ImGui_ImplWin32_DestroyWindow ( ImGuiViewport * viewport )
2018-02-27 23:26:51 +01:00
{
2018-03-18 22:19:02 +01:00
if ( ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData )
2018-02-27 23:26:51 +01:00
{
if ( : : GetCapture ( ) = = data - > Hwnd )
{
2018-04-10 22:58:39 +02:00
// Transfer capture so if we started dragging from a window that later disappears, we'll still receive the MOUSEUP event.
2018-02-27 23:26:51 +01:00
: : ReleaseCapture ( ) ;
: : SetCapture ( g_hWnd ) ;
}
2018-04-09 22:01:24 +02:00
if ( data - > Hwnd & & data - > HwndOwned )
2018-02-27 23:26:51 +01:00
: : DestroyWindow ( data - > Hwnd ) ;
data - > Hwnd = NULL ;
IM_DELETE ( data ) ;
}
viewport - > PlatformUserData = viewport - > PlatformHandle = NULL ;
}
static void ImGui_ImplWin32_ShowWindow ( ImGuiViewport * viewport )
{
2018-03-18 22:19:02 +01:00
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
2018-02-27 23:26:51 +01:00
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
if ( viewport - > Flags & ImGuiViewportFlags_NoFocusOnAppearing )
: : ShowWindow ( data - > Hwnd , SW_SHOWNA ) ;
else
: : ShowWindow ( data - > Hwnd , SW_SHOW ) ;
}
2019-01-02 16:06:58 +01:00
static void ImGui_ImplWin32_UpdateWindow ( ImGuiViewport * viewport )
{
2019-09-17 16:35:50 +02:00
// (Optional) Update Win32 style if it changed _after_ creation.
2019-01-02 16:06:58 +01:00
// Generally they won't change unless configuration flags are changed, but advanced uses (such as manually rewriting viewport flags) make this useful.
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
DWORD new_style ;
DWORD new_ex_style ;
ImGui_ImplWin32_GetWin32StyleFromViewportFlags ( viewport - > Flags , & new_style , & new_ex_style ) ;
// Only reapply the flags that have been changed from our point of view (as other flags are being modified by Windows)
if ( data - > DwStyle ! = new_style | | data - > DwExStyle ! = new_ex_style )
{
2020-09-17 02:58:23 +02:00
// (Optional) Update TopMost state if it changed _after_ creation
bool top_most_changed = ( data - > DwExStyle & WS_EX_TOPMOST ) ! = ( new_ex_style & WS_EX_TOPMOST ) ;
HWND insert_after = top_most_changed ? ( ( viewport - > Flags & ImGuiViewportFlags_TopMost ) ? HWND_TOPMOST : HWND_NOTOPMOST ) : 0 ;
UINT swp_flag = top_most_changed ? 0 : SWP_NOZORDER ;
// Apply flags and position (since it is affected by flags)
2019-01-02 16:06:58 +01:00
data - > DwStyle = new_style ;
data - > DwExStyle = new_ex_style ;
: : SetWindowLong ( data - > Hwnd , GWL_STYLE , data - > DwStyle ) ;
: : SetWindowLong ( data - > Hwnd , GWL_EXSTYLE , data - > DwExStyle ) ;
RECT rect = { ( LONG ) viewport - > Pos . x , ( LONG ) viewport - > Pos . y , ( LONG ) ( viewport - > Pos . x + viewport - > Size . x ) , ( LONG ) ( viewport - > Pos . y + viewport - > Size . y ) } ;
: : AdjustWindowRectEx ( & rect , data - > DwStyle , FALSE , data - > DwExStyle ) ; // Client to Screen
2020-09-17 02:58:23 +02:00
: : SetWindowPos ( data - > Hwnd , insert_after , rect . left , rect . top , rect . right - rect . left , rect . bottom - rect . top , swp_flag | SWP_NOACTIVATE | SWP_FRAMECHANGED ) ;
2019-01-02 16:06:58 +01:00
: : ShowWindow ( data - > Hwnd , SW_SHOWNA ) ; // This is necessary when we alter the style
viewport - > PlatformRequestMove = viewport - > PlatformRequestResize = true ;
}
}
2018-02-27 23:26:51 +01:00
static ImVec2 ImGui_ImplWin32_GetWindowPos ( ImGuiViewport * viewport )
{
2018-03-18 22:19:02 +01:00
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
2018-02-27 23:26:51 +01:00
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
POINT pos = { 0 , 0 } ;
: : ClientToScreen ( data - > Hwnd , & pos ) ;
return ImVec2 ( ( float ) pos . x , ( float ) pos . y ) ;
}
static void ImGui_ImplWin32_SetWindowPos ( ImGuiViewport * viewport , ImVec2 pos )
{
2018-03-18 22:19:02 +01:00
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
2018-02-27 23:26:51 +01:00
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
RECT rect = { ( LONG ) pos . x , ( LONG ) pos . y , ( LONG ) pos . x , ( LONG ) pos . y } ;
: : AdjustWindowRectEx ( & rect , data - > DwStyle , FALSE , data - > DwExStyle ) ;
: : SetWindowPos ( data - > Hwnd , NULL , rect . left , rect . top , 0 , 0 , SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE ) ;
}
static ImVec2 ImGui_ImplWin32_GetWindowSize ( ImGuiViewport * viewport )
{
2018-03-18 22:19:02 +01:00
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
2018-02-27 23:26:51 +01:00
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
RECT rect ;
: : GetClientRect ( data - > Hwnd , & rect ) ;
return ImVec2 ( float ( rect . right - rect . left ) , float ( rect . bottom - rect . top ) ) ;
}
static void ImGui_ImplWin32_SetWindowSize ( ImGuiViewport * viewport , ImVec2 size )
{
2018-03-18 22:19:02 +01:00
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
2018-02-27 23:26:51 +01:00
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
RECT rect = { 0 , 0 , ( LONG ) size . x , ( LONG ) size . y } ;
: : AdjustWindowRectEx ( & rect , data - > DwStyle , FALSE , data - > DwExStyle ) ; // Client to Screen
: : SetWindowPos ( data - > Hwnd , NULL , 0 , 0 , rect . right - rect . left , rect . bottom - rect . top , SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE ) ;
}
2018-04-25 15:15:14 +02:00
static void ImGui_ImplWin32_SetWindowFocus ( ImGuiViewport * viewport )
{
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
: : BringWindowToTop ( data - > Hwnd ) ;
: : SetForegroundWindow ( data - > Hwnd ) ;
: : SetFocus ( data - > Hwnd ) ;
}
static bool ImGui_ImplWin32_GetWindowFocus ( ImGuiViewport * viewport )
{
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
2019-01-15 21:22:21 +01:00
return : : GetForegroundWindow ( ) = = data - > Hwnd ;
2018-04-25 15:15:14 +02:00
}
2018-11-23 16:18:30 +01:00
static bool ImGui_ImplWin32_GetWindowMinimized ( ImGuiViewport * viewport )
{
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
return : : IsIconic ( data - > Hwnd ) ! = 0 ;
}
2018-02-27 23:26:51 +01:00
static void ImGui_ImplWin32_SetWindowTitle ( ImGuiViewport * viewport , const char * title )
{
2018-11-05 17:37:06 +01:00
// ::SetWindowTextA() doesn't properly handle UTF-8 so we explicitely convert our string.
2018-03-18 22:19:02 +01:00
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
2018-02-27 23:26:51 +01:00
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
2018-11-05 17:37:06 +01:00
int n = : : MultiByteToWideChar ( CP_UTF8 , 0 , title , - 1 , NULL , 0 ) ;
ImVector < wchar_t > title_w ;
title_w . resize ( n ) ;
: : MultiByteToWideChar ( CP_UTF8 , 0 , title , - 1 , title_w . Data , n ) ;
: : SetWindowTextW ( data - > Hwnd , title_w . Data ) ;
2018-02-27 23:26:51 +01:00
}
2018-04-05 17:06:23 +02:00
static void ImGui_ImplWin32_SetWindowAlpha ( ImGuiViewport * viewport , float alpha )
{
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
IM_ASSERT ( alpha > = 0.0f & & alpha < = 1.0f ) ;
if ( alpha < 1.0f )
{
DWORD style = : : GetWindowLongW ( data - > Hwnd , GWL_EXSTYLE ) | WS_EX_LAYERED ;
: : SetWindowLongW ( data - > Hwnd , GWL_EXSTYLE , style ) ;
: : SetLayeredWindowAttributes ( data - > Hwnd , 0 , ( BYTE ) ( 255 * alpha ) , LWA_ALPHA ) ;
}
else
{
DWORD style = : : GetWindowLongW ( data - > Hwnd , GWL_EXSTYLE ) & ~ WS_EX_LAYERED ;
: : SetWindowLongW ( data - > Hwnd , GWL_EXSTYLE , style ) ;
}
}
2018-03-09 19:08:47 +01:00
static float ImGui_ImplWin32_GetWindowDpiScale ( ImGuiViewport * viewport )
{
2018-03-18 22:19:02 +01:00
ImGuiViewportDataWin32 * data = ( ImGuiViewportDataWin32 * ) viewport - > PlatformUserData ;
2018-12-14 11:59:44 +01:00
IM_ASSERT ( data - > Hwnd ! = 0 ) ;
return ImGui_ImplWin32_GetDpiScaleForHwnd ( data - > Hwnd ) ;
2018-03-09 19:08:47 +01:00
}
2018-04-23 18:27:38 +02:00
// FIXME-DPI: Testing DPI related ideas
static void ImGui_ImplWin32_OnChangedViewport ( ImGuiViewport * viewport )
{
( void ) viewport ;
#if 0
ImGuiStyle default_style ;
//default_style.WindowPadding = ImVec2(0, 0);
//default_style.WindowBorderSize = 0.0f;
//default_style.ItemSpacing.y = 3.0f;
//default_style.FramePadding = ImVec2(0, 0);
default_style . ScaleAllSizes ( viewport - > DpiScale ) ;
ImGuiStyle & style = ImGui : : GetStyle ( ) ;
style = default_style ;
# endif
}
2018-02-27 23:26:51 +01:00
static LRESULT CALLBACK ImGui_ImplWin32_WndProcHandler_PlatformWindow ( HWND hWnd , UINT msg , WPARAM wParam , LPARAM lParam )
{
if ( ImGui_ImplWin32_WndProcHandler ( hWnd , msg , wParam , lParam ) )
return true ;
if ( ImGuiViewport * viewport = ImGui : : FindViewportByPlatformHandle ( ( void * ) hWnd ) )
{
switch ( msg )
{
case WM_CLOSE :
viewport - > PlatformRequestClose = true ;
return 0 ;
case WM_MOVE :
2018-03-15 10:54:27 +01:00
viewport - > PlatformRequestMove = true ;
break ;
case WM_SIZE :
viewport - > PlatformRequestResize = true ;
2018-02-27 23:26:51 +01:00
break ;
2019-01-30 21:21:59 +01:00
case WM_MOUSEACTIVATE :
if ( viewport - > Flags & ImGuiViewportFlags_NoFocusOnClick )
return MA_NOACTIVATE ;
break ;
2018-02-27 23:26:51 +01:00
case WM_NCHITTEST :
2020-10-14 14:43:45 +02:00
// Let mouse pass-through the window. This will allow the backend to set io.MouseHoveredViewport properly (which is OPTIONAL).
2018-04-05 12:00:07 +02:00
// The ImGuiViewportFlags_NoInputs flag is set while dragging a viewport, as want to detect the window behind the one we are dragging.
// If you cannot easily access those viewport flags from your windowing/event code: you may manually synchronize its state e.g. in
2020-03-06 17:53:09 +01:00
// your main loop after calling UpdatePlatformWindows(). Iterate all viewports/platform windows and pass the flag to your windowing system.
2018-02-27 23:26:51 +01:00
if ( viewport - > Flags & ImGuiViewportFlags_NoInputs )
return HTTRANSPARENT ;
break ;
}
}
return DefWindowProc ( hWnd , msg , wParam , lParam ) ;
}
static void ImGui_ImplWin32_InitPlatformInterface ( )
{
WNDCLASSEX wcex ;
wcex . cbSize = sizeof ( WNDCLASSEX ) ;
wcex . style = CS_HREDRAW | CS_VREDRAW ;
wcex . lpfnWndProc = ImGui_ImplWin32_WndProcHandler_PlatformWindow ;
wcex . cbClsExtra = 0 ;
wcex . cbWndExtra = 0 ;
wcex . hInstance = : : GetModuleHandle ( NULL ) ;
wcex . hIcon = NULL ;
wcex . hCursor = NULL ;
wcex . hbrBackground = ( HBRUSH ) ( COLOR_BACKGROUND + 1 ) ;
wcex . lpszMenuName = NULL ;
wcex . lpszClassName = _T ( " ImGui Platform " ) ;
wcex . hIconSm = NULL ;
: : RegisterClassEx ( & wcex ) ;
2018-04-10 22:32:08 +02:00
ImGui_ImplWin32_UpdateMonitors ( ) ;
2018-02-27 23:26:51 +01:00
// Register platform interface (will be coupled with a renderer interface)
2018-03-18 18:44:57 +01:00
ImGuiPlatformIO & platform_io = ImGui : : GetPlatformIO ( ) ;
platform_io . Platform_CreateWindow = ImGui_ImplWin32_CreateWindow ;
platform_io . Platform_DestroyWindow = ImGui_ImplWin32_DestroyWindow ;
platform_io . Platform_ShowWindow = ImGui_ImplWin32_ShowWindow ;
platform_io . Platform_SetWindowPos = ImGui_ImplWin32_SetWindowPos ;
platform_io . Platform_GetWindowPos = ImGui_ImplWin32_GetWindowPos ;
platform_io . Platform_SetWindowSize = ImGui_ImplWin32_SetWindowSize ;
platform_io . Platform_GetWindowSize = ImGui_ImplWin32_GetWindowSize ;
2018-04-25 15:15:14 +02:00
platform_io . Platform_SetWindowFocus = ImGui_ImplWin32_SetWindowFocus ;
platform_io . Platform_GetWindowFocus = ImGui_ImplWin32_GetWindowFocus ;
2018-11-23 16:18:30 +01:00
platform_io . Platform_GetWindowMinimized = ImGui_ImplWin32_GetWindowMinimized ;
2018-03-18 18:44:57 +01:00
platform_io . Platform_SetWindowTitle = ImGui_ImplWin32_SetWindowTitle ;
2018-04-05 17:06:23 +02:00
platform_io . Platform_SetWindowAlpha = ImGui_ImplWin32_SetWindowAlpha ;
2019-01-02 16:06:58 +01:00
platform_io . Platform_UpdateWindow = ImGui_ImplWin32_UpdateWindow ;
2018-12-14 11:59:44 +01:00
platform_io . Platform_GetWindowDpiScale = ImGui_ImplWin32_GetWindowDpiScale ; // FIXME-DPI
2018-04-23 18:27:38 +02:00
platform_io . Platform_OnChangedViewport = ImGui_ImplWin32_OnChangedViewport ; // FIXME-DPI
2018-04-24 12:40:38 +02:00
# if HAS_WIN32_IME
platform_io . Platform_SetImeInputPos = ImGui_ImplWin32_SetImeInputPos ;
# endif
2018-02-27 23:26:51 +01:00
2018-04-09 22:01:24 +02:00
// Register main window handle (which is owned by the main application, not by us)
2020-01-20 19:33:46 +01:00
// This is mostly for simplicity and consistency, so that our code (e.g. mouse handling etc.) can use same logic for main and secondary viewports.
2018-02-27 23:26:51 +01:00
ImGuiViewport * main_viewport = ImGui : : GetMainViewport ( ) ;
2018-03-18 22:19:02 +01:00
ImGuiViewportDataWin32 * data = IM_NEW ( ImGuiViewportDataWin32 ) ( ) ;
2018-02-27 23:26:51 +01:00
data - > Hwnd = g_hWnd ;
2018-04-09 22:01:24 +02:00
data - > HwndOwned = false ;
2018-02-27 23:26:51 +01:00
main_viewport - > PlatformUserData = data ;
2018-04-09 22:01:24 +02:00
main_viewport - > PlatformHandle = ( void * ) g_hWnd ;
2018-02-27 23:26:51 +01:00
}
static void ImGui_ImplWin32_ShutdownPlatformInterface ( )
{
: : UnregisterClass ( _T ( " ImGui Platform " ) , : : GetModuleHandle ( NULL ) ) ;
}
2020-02-17 18:33:59 +01:00
2020-02-17 11:11:08 +01:00
//---------------------------------------------------------------------------------------------------------