diff --git a/examples/imgui_impl_glfw.cpp b/examples/imgui_impl_glfw.cpp index 4d54f501..416e0f99 100644 --- a/examples/imgui_impl_glfw.cpp +++ b/examples/imgui_impl_glfw.cpp @@ -41,8 +41,10 @@ #define GLFW_HAS_GLFW_HOVERED 0 #endif #define GLFW_HAS_WINDOW_ALPHA (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3300) // 3.3+ +#define GLFW_HAS_WINDOW_TOPMOST (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ #define GLFW_HAS_VULKAN (GLFW_VERSION_MAJOR * 1000 + GLFW_VERSION_MINOR * 100 >= 3200) // 3.2+ + // Data enum GlfwClientApi { @@ -357,6 +359,9 @@ static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport) glfwWindowHint(GLFW_VISIBLE, false); glfwWindowHint(GLFW_FOCUSED, false); glfwWindowHint(GLFW_DECORATED, (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? false : true); +#if GLFW_HAS_WINDOW_TOPMOST + glfwWindowHint(GLFW_FLOATING, (viewport->Flags & imGuiViewportFlags_TopMost) ? true : false); +#endif GLFWwindow* share_window = (g_ClientApi == GlfwClientApi_OpenGL) ? g_Window : NULL; data->Window = glfwCreateWindow((int)viewport->Size.x, (int)viewport->Size.y, "No Title Yet", NULL, share_window); data->WindowOwned = true; @@ -373,7 +378,7 @@ static void ImGui_ImplGlfw_DestroyWindow(ImGuiViewport* viewport) { if (data->WindowOwned) { -#if GLFW_HAS_GLFW_HOVERED +#if GLFW_HAS_GLFW_HOVERED && defined(_WIN32) HWND hwnd = glfwGetWin32Window(data->Window); ::RemovePropA(hwnd, "IMGUI_VIEWPORT"); #endif @@ -419,7 +424,7 @@ static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport) } // GLFW hack: install hook for WM_NCHITTEST message handler -#if GLFW_HAS_GLFW_HOVERED +#if GLFW_HAS_GLFW_HOVERED && defined(_WIN32) ::SetPropA(hwnd, "IMGUI_VIEWPORT", viewport); if (g_GlfwWndProc == NULL) g_GlfwWndProc = (WNDPROC)::GetWindowLongPtr(hwnd, GWLP_WNDPROC); diff --git a/examples/imgui_impl_sdl2.cpp b/examples/imgui_impl_sdl2.cpp index 9bea456b..e01bd79d 100644 --- a/examples/imgui_impl_sdl2.cpp +++ b/examples/imgui_impl_sdl2.cpp @@ -34,6 +34,7 @@ #include #define SDL_HAS_CAPTURE_MOUSE SDL_VERSION_ATLEAST(2,0,4) #define SDL_HAS_WINDOW_OPACITY SDL_VERSION_ATLEAST(2,0,5) +#define SDL_HAS_ALWAYS_ON_TOP SDL_VERSION_ATLEAST(2,0,5) #define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6) #if !SDL_HAS_VULKAN static const Uint32 SDL_WINDOW_VULKAN = 0x10000000; @@ -317,6 +318,9 @@ static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport) sdl_flags |= SDL_WINDOW_HIDDEN; sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? SDL_WINDOW_BORDERLESS : 0; sdl_flags |= (viewport->Flags & ImGuiViewportFlags_NoDecoration) ? 0 : SDL_WINDOW_RESIZABLE; +#if SDL_HAS_ALWAYS_ON_TOP + sdl_flags |= (viewport->Flags & imGuiViewportFlags_TopMost) ? SDL_WINDOW_ALWAYS_ON_TOP : 0; +#endif data->Window = SDL_CreateWindow("No Title Yet", (int)viewport->PlatformPos.x, (int)viewport->PlatformPos.y, (int)viewport->Size.x, (int)viewport->Size.y, sdl_flags); data->WindowOwned = true; if (use_opengl) diff --git a/examples/imgui_impl_win32.cpp b/examples/imgui_impl_win32.cpp index bf440bd5..610a2e23 100644 --- a/examples/imgui_impl_win32.cpp +++ b/examples/imgui_impl_win32.cpp @@ -389,6 +389,8 @@ static void ImGui_ImplWin32_CreateWindow(ImGuiViewport* viewport) data->DwStyle = WS_OVERLAPPEDWINDOW; data->DwExStyle = no_task_bar_icon ? WS_EX_TOOLWINDOW : WS_EX_APPWINDOW; } + if (viewport->Flags & imGuiViewportFlags_TopMost) + data->DwExStyle |= WS_EX_TOPMOST; // Create window RECT rect = { (LONG)viewport->PlatformPos.x, (LONG)viewport->PlatformPos.y, (LONG)(viewport->PlatformPos.x + viewport->Size.x), (LONG)(viewport->PlatformPos.y + viewport->Size.y) }; diff --git a/imgui.cpp b/imgui.cpp index 7ffffe7e..1ecc8dfb 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -434,7 +434,7 @@ perfectly fine, as the bool toggle fairly rarely. If you have on a touch device, you might find use for an early call to NewFrameUpdateHoveredWindowAndCaptureFlags(). Note: Text input widget releases focus on "Return KeyDown", so the subsequent "Return KeyUp" event that your application receive will typically have 'io.WantCaptureKeyboard=false'. Depending on your application logic it may or not be inconvenient. You might want to track which key-downs - were targetted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.) + were targeted for Dear ImGui, e.g. with an array of bool, and filter out the corresponding key-ups.) Q: How can I display an image? What is ImTextureID, how does it works? A: ImTextureID is a void* used to pass renderer-agnostic texture references around until it hits your render function. @@ -766,7 +766,7 @@ const ImGuiID IMGUI_VIEWPORT_DEFAULT_ID = 0x11111111; // Using an arbi static inline ImRect GetViewportRect(ImGuiWindow* window) { return window->Viewport->GetRect(); } static inline ImVec2 ConvertViewportPosToPlatformPos(const ImVec2& imgui_pos, ImGuiViewport* viewport) { return imgui_pos - viewport->Pos + viewport->PlatformPos; } static inline ImVec2 ConvertPlatformPosToViewportPos(const ImVec2& platform_pos, ImGuiViewport* viewport) { return platform_pos - viewport->PlatformPos + viewport->Pos; } -static ImGuiViewportP* Viewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFlags flags, const ImVec2& platform_pos, const ImVec2& size); +static ImGuiViewportP* AddViewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFlags flags, const ImVec2& platform_pos, const ImVec2& size); static void UpdateViewports(); static void UpdateSelectWindowViewport(ImGuiWindow* window); static void SetCurrentViewport(ImGuiViewportP* viewport); @@ -3330,7 +3330,7 @@ static void ImGui::NewFrameUpdateMovingWindowDropViewport(ImGuiWindow* window) { // Create/persist new viewport ImVec2 platform_pos = ConvertViewportPosToPlatformPos(window->Pos, window->Viewport); - ImGuiViewportP* viewport = Viewport(window, window->ID, 0, platform_pos, window->Size); + ImGuiViewportP* viewport = AddViewport(window, window->ID, 0, platform_pos, window->Size); SetWindowViewportTranslateToPreservePlatformPos(window, window->Viewport, viewport); } } @@ -3475,7 +3475,7 @@ static void ImGui::UpdateViewports() ImVec2 main_viewport_platform_pos = ImVec2(0.0f, 0.0f); if ((g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) main_viewport_platform_pos = g.PlatformIO.Platform_GetWindowPos(main_viewport); - Viewport(NULL, IMGUI_VIEWPORT_DEFAULT_ID, ImGuiViewportFlags_CanHostOtherWindows, main_viewport_platform_pos, g.IO.DisplaySize); + AddViewport(NULL, IMGUI_VIEWPORT_DEFAULT_ID, ImGuiViewportFlags_CanHostOtherWindows, main_viewport_platform_pos, g.IO.DisplaySize); if (!(g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)) { @@ -3560,10 +3560,16 @@ void ImGui::UpdatePlatformWindows() continue; } - // Update ImGuiViewportFlags_NoTaskBarIcon flag + // New windows that appears directly in a new viewport won't always have a size on their frame + if (viewport->Size.x <= 0 || viewport->Size.y <= 0) + continue; + + // Update viewport flags if (viewport->Window != NULL) { + bool topmost = (viewport->Window->Flags & ImGuiWindowFlags_Tooltip) != 0; bool no_task_bar_icon = (g.IO.ConfigFlags & ImGuiConfigFlags_ViewportsNoTaskBarIcons) != 0 || (viewport->Window->Flags & (ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_Popup)) != 0; + viewport->Flags = topmost ? (viewport->Flags | imGuiViewportFlags_TopMost) : (viewport->Flags & ~imGuiViewportFlags_TopMost); viewport->Flags = no_task_bar_icon ? (viewport->Flags | ImGuiViewportFlags_NoTaskBarIcon) : (viewport->Flags & ~ImGuiViewportFlags_NoTaskBarIcon); } @@ -4506,7 +4512,7 @@ void ImGui::EndFrame() for (int i = 0; i < g.Viewports.Size; i++) { ImGuiViewportP* viewport = g.Viewports[i]; - if (viewport->LastFrameActive < g.FrameCount) + if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f) continue; if (i > 0) IM_ASSERT(viewport->Window != NULL); @@ -4679,7 +4685,7 @@ void ImGui::SetCurrentViewport(ImGuiViewportP* viewport) g.PlatformIO.Platform_OnChangedViewport(g.CurrentViewport); } -ImGuiViewportP* ImGui::Viewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFlags flags, const ImVec2& platform_pos, const ImVec2& size) +ImGuiViewportP* ImGui::AddViewport(ImGuiWindow* window, ImGuiID id, ImGuiViewportFlags flags, const ImVec2& platform_pos, const ImVec2& size) { ImGuiContext& g = *GImGui; IM_ASSERT(id != 0); @@ -6164,7 +6170,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window) window->Viewport = FindViewportByID(window->ViewportId); if (window->Viewport == NULL && window->ViewportPlatformPos.x != FLT_MAX && window->ViewportPlatformPos.y != FLT_MAX) { - ImGuiViewportP* viewport = Viewport(window, window->ID, ImGuiViewportFlags_NoDecoration, window->ViewportPlatformPos, window->Size); + ImGuiViewportP* viewport = AddViewport(window, window->ID, ImGuiViewportFlags_NoDecoration, window->ViewportPlatformPos, window->Size); window->Flags |= ImGuiWindowFlags_FullViewport; window->Viewport = viewport; created_viewport = true; @@ -6189,7 +6195,7 @@ static void ImGui::UpdateSelectWindowViewport(ImGuiWindow* window) // Calculate mouse position in OS/platform coordinates, create a Viewport at this position. ImVec2 platform_pos = ConvertViewportPosToPlatformPos(g.IO.MousePos - g.ActiveIdClickOffset, g.MousePosViewport); ImGuiViewportFlags viewport_flags = ImGuiViewportFlags_NoDecoration | ImGuiViewportFlags_NoFocusOnAppearing | ImGuiViewportFlags_NoInputs; - ImGuiViewportP* viewport = Viewport(window, window->ID, viewport_flags, platform_pos, window->Size); + ImGuiViewportP* viewport = AddViewport(window, window->ID, viewport_flags, platform_pos, window->Size); window->Flags |= ImGuiWindowFlags_FullViewport; window->Viewport = viewport; created_viewport = true; diff --git a/imgui.h b/imgui.h index 90892e6e..6b4781d0 100644 --- a/imgui.h +++ b/imgui.h @@ -1937,7 +1937,8 @@ enum ImGuiViewportFlags_ ImGuiViewportFlags_NoFocusOnAppearing = 1 << 1, // Platform Window: Don't take focus when created. ImGuiViewportFlags_NoInputs = 1 << 2, // Platform Window: Make mouse pass through so we can drag this window while peaking behind it. ImGuiViewportFlags_NoTaskBarIcon = 1 << 3, // Platform Window: Disable platform task bar icon (for popups, menus, or all windows if ImGuiConfigFlags_ViewportsNoTaskBarIcons if set) - ImGuiViewportFlags_NoRendererClear = 1 << 4 // Platform Window: Renderer doesn't need to clear the framebuffer ahead. + ImGuiViewportFlags_NoRendererClear = 1 << 4, // Platform Window: Renderer doesn't need to clear the framebuffer ahead. + imGuiViewportFlags_TopMost = 1 << 5 // Platform Window: Display on top (for tooltips only) }; // The viewports created and managed by imgui. The role of the platform back-end is to create the platform/OS windows corresponding to each viewport.