diff --git a/application/editormode.cpp b/application/editormode.cpp index cc7a1bee..adfb1340 100644 --- a/application/editormode.cpp +++ b/application/editormode.cpp @@ -3190,7 +3190,7 @@ void editor_mode::draw_area_fill_outline() const }; float constexpr nearw = 0.1f; - ImDrawList *drawlist = ImGui::GetBackgroundDrawList(); + ImDrawList *drawlist = ImGui::GetBackgroundDrawList(ImGui::GetMainViewport()); ImU32 const edgecolor = IM_COL32(255, 200, 40, 230); ImU32 const closingcolor = IM_COL32(255, 200, 40, 110); diff --git a/application/editormodeinfra.cpp b/application/editormodeinfra.cpp index 86ae5389..1e18d042 100644 --- a/application/editormodeinfra.cpp +++ b/application/editormodeinfra.cpp @@ -1633,7 +1633,7 @@ void editor_mode::draw_infra_overlay() const return; Live.refresh(); screen_projection const projection; - ImDrawList *drawlist{ImGui::GetBackgroundDrawList()}; + ImDrawList *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; auto const camera{GfxRenderer->Camera_Position()}; auto const draw = [&](infra::binding const &Binding, ImU32 const Colour, float const Size) { if (Binding.anchors.empty() || glm::distance(Binding.anchors.front().foot, camera) > 2000.0) diff --git a/application/editormodejoints.cpp b/application/editormodejoints.cpp index acb9e8f2..c50d9d82 100644 --- a/application/editormodejoints.cpp +++ b/application/editormodejoints.cpp @@ -504,7 +504,7 @@ void editor_mode::draw_joints_overlay() const if (false == state.open || state.issues.empty()) return; screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; glm::dvec3 const camera{Global.pCamera.Pos}; for (int i = 0; i < static_cast(state.issues.size()); ++i) { diff --git a/application/editormodelineside.cpp b/application/editormodelineside.cpp index 37d793d3..f28ff72a 100644 --- a/application/editormodelineside.cpp +++ b/application/editormodelineside.cpp @@ -688,7 +688,7 @@ void editor_mode::draw_hekto_overlay() const if (false == tool.open || tool.track == nullptr) return; screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; glm::dvec3 const camera{Global.pCamera.Pos}; for (auto const &post : tool.posts) { @@ -955,7 +955,7 @@ void editor_mode::draw_fouling_overlay() const if (false == tool.open) return; screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; glm::dvec3 const camera{Global.pCamera.Pos}; for (auto const &point : tool.points) { diff --git a/application/editormodeparallel.cpp b/application/editormodeparallel.cpp index 7eaa92f4..47222bb7 100644 --- a/application/editormodeparallel.cpp +++ b/application/editormodeparallel.cpp @@ -215,7 +215,7 @@ void editor_mode::draw_parallel_preview() const if (false == tool.open || tool.pieces.empty() || selected_track() != tool.built_for) return; screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; for (auto const &piece : tool.pieces) { bezier const curve{piece}; diff --git a/application/editormodeprofile.cpp b/application/editormodeprofile.cpp index e1976b2d..974482cb 100644 --- a/application/editormodeprofile.cpp +++ b/application/editormodeprofile.cpp @@ -1885,7 +1885,7 @@ void editor_mode::draw_profile_overlay() const if (false == state.open || state.samples.size() < 2) return; screen_projection const projection; - ImDrawList *drawlist{ImGui::GetBackgroundDrawList()}; + ImDrawList *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; auto const &samples{state.samples}; glm::dvec3 previous{samples.front().position}; glm::dvec3 designedprevious{previous.x, profile::elevation(state.line, 0.0), previous.z}; diff --git a/application/editormoderoad.cpp b/application/editormoderoad.cpp index e9e13495..d66b6bcb 100644 --- a/application/editormoderoad.cpp +++ b/application/editormoderoad.cpp @@ -2505,7 +2505,7 @@ void editor_mode::draw_road_overlay() const return; screen_projection projection; - ImDrawList *drawlist = ImGui::GetBackgroundDrawList(); + ImDrawList *drawlist = ImGui::GetBackgroundDrawList(ImGui::GetMainViewport()); glm::dvec3 const camera{Global.pCamera.Pos}; // pieces of a line needed to draw a path: one for a straight, more the longer a bend is and the nearer it is auto const pieces = [&camera](segment_data const &Path, glm::dvec3 const &Location) { diff --git a/application/editormodesignal.cpp b/application/editormodesignal.cpp index d071f942..53840611 100644 --- a/application/editormodesignal.cpp +++ b/application/editormodesignal.cpp @@ -947,7 +947,7 @@ void editor_mode::draw_signal_overlay() const { auto const &tool{m_signal}; screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; glm::dvec3 const camera{Global.pCamera.Pos}; auto const arrow = [&](glm::dvec3 const &From, glm::dvec2 const &Direction, ImU32 const Colour) { glm::dvec3 const tip{From.x + Direction.x * 6.0, From.y, From.z + Direction.y * 6.0}; diff --git a/application/editormodespeed.cpp b/application/editormodespeed.cpp index 52b39f46..9843c7b0 100644 --- a/application/editormodespeed.cpp +++ b/application/editormodespeed.cpp @@ -349,7 +349,7 @@ void editor_mode::draw_speed_overlay() const if (false == state.open || state.results.empty()) return; screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; glm::dvec3 const camera{Global.pCamera.Pos}; for (int i = 0; i < static_cast(state.results.size()); ++i) { diff --git a/application/editormodesweep.cpp b/application/editormodesweep.cpp index ed5e10dc..b5fed509 100644 --- a/application/editormodesweep.cpp +++ b/application/editormodesweep.cpp @@ -986,7 +986,7 @@ void editor_mode::draw_sweep_overlay() const if (false == tool.open || tool.outline.size() < 2) return; screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; auto const &settings{tool.settings}; auto const from{std::max(0.0, settings.from)}; auto const to{settings.to < 0.0 ? tool.curve_length : std::min(settings.to, tool.curve_length)}; @@ -1820,7 +1820,7 @@ void editor_mode::draw_bend_overlay() const if (false == tool.label.empty()) { auto const &io{ImGui::GetIO()}; - auto *foreground{ImGui::GetForegroundDrawList()}; + auto *foreground{ImGui::GetForegroundDrawList(ImGui::GetMainViewport())}; auto const labelsize{ImGui::CalcTextSize(tool.label.c_str())}; auto const detailsize{tool.details.empty() ? ImVec2(0.0f, 0.0f) : ImGui::CalcTextSize(tool.details.c_str())}; ImVec2 const size{std::max(labelsize.x, detailsize.x), labelsize.y + (tool.details.empty() ? 0.0f : detailsize.y + 4.0f)}; @@ -1839,7 +1839,7 @@ void editor_mode::draw_bend_overlay() const if (projection.project(model->location(), at)) { auto const text{format(STR_C("B: bend along %s"), tool.tracks.front().first->name().c_str())}; - auto *foreground{ImGui::GetForegroundDrawList()}; + auto *foreground{ImGui::GetForegroundDrawList(ImGui::GetMainViewport())}; auto const size{ImGui::CalcTextSize(text.c_str())}; foreground->AddRectFilled(ImVec2(at.x + 10.0f, at.y - size.y - 14.0f), ImVec2(at.x + size.x + 22.0f, at.y - 6.0f), IM_COL32(0, 0, 0, 150), 4.0f); foreground->AddText(ImVec2(at.x + 16.0f, at.y - size.y - 10.0f), IM_COL32(40, 220, 255, 255), text.c_str()); @@ -1856,7 +1856,7 @@ void editor_mode::draw_bend_overlay() const ImVec2 screen; if (false == projection.project(marker, screen)) return; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; if (tool.over_marker || tool.dragging != 0) drawlist->AddCircleFilled(screen, 9.0f, IM_COL32(40, 220, 255, 120), 16); drawlist->AddCircle(screen, 9.0f, IM_COL32(40, 220, 255, 255), 16, 2.5f); diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index ee91503e..761b36ab 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -269,7 +269,7 @@ void editor_mode::draw_track_overlay() const return; screen_projection const projection; - ImDrawList *drawlist = ImGui::GetBackgroundDrawList(); + ImDrawList *drawlist = ImGui::GetBackgroundDrawList(ImGui::GetMainViewport()); bool const trackmode = ui()->mode() == nodebank_panel::TRACK; ImU32 const coursecolor = IM_COL32(40, 220, 255, 220); @@ -2042,7 +2042,7 @@ void editor_mode::draw_route_overlay() const auto const &design{route.design}; auto const &result{route.result}; screen_projection const projection; - ImDrawList *drawlist = ImGui::GetBackgroundDrawList(); + ImDrawList *drawlist = ImGui::GetBackgroundDrawList(ImGui::GetMainViewport()); auto const &start{result.valid ? result.start : design.start}; auto const &end{result.valid ? result.end : design.end}; @@ -2415,7 +2415,7 @@ editor_track::straight const &editor_mode::current_straight() void editor_mode::draw_straights_overlay() const { screen_projection const projection; - ImDrawList *drawlist = ImGui::GetBackgroundDrawList(); + ImDrawList *drawlist = ImGui::GetBackgroundDrawList(ImGui::GetMainViewport()); glm::dvec3 const camera{Global.pCamera.Pos}; auto const nearby = [&](editor_track::straight const &Line) { auto const offset{camera - Line.start}; @@ -3641,7 +3641,7 @@ std::string editor_mode::track_readout() const void editor_mode::draw_track_hints() { ImGuiIO const &io = ImGui::GetIO(); - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; float const margin{12.0f}; float const gap{14.0f}; float const pad{4.0f}; @@ -3698,7 +3698,7 @@ void editor_mode::draw_track_hints() readout += (readout.empty() ? "" : "\n") + std::string{"= "} + m_typed + "_ " + STR(meaning); if (readout.empty() || ImGui::GetIO().WantCaptureMouse) return; - auto *foreground{ImGui::GetForegroundDrawList()}; + auto *foreground{ImGui::GetForegroundDrawList(ImGui::GetMainViewport())}; auto const size{ImGui::CalcTextSize(readout.c_str())}; ImVec2 at{io.MousePos.x + 20.0f, io.MousePos.y + 20.0f}; at.x = std::min(at.x, io.DisplaySize.x - size.x - 10.0f); @@ -3873,7 +3873,7 @@ editor_track::snap_target editor_mode::snap_free_end(glm::dvec3 const &Near, glm void editor_mode::draw_free_ends(TTrack const *Self, int const Category, std::vector const &Exclude) const { screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; auto const &display{ImGui::GetIO().DisplaySize}; auto const reach{Global.EditorOrtho ? std::max(kJointRange, static_cast(Global.EditorOrthoExtent) * 2.0) : kJointRange}; for (auto const &candidate : editor_track::free_ends(Self, Category, glm::dvec3{Global.pCamera.Pos}, reach, Exclude)) @@ -4971,7 +4971,7 @@ bool editor_mode::place_switch_on_straight(editor_track::straight const &Line, e void editor_mode::draw_build_overlay() const { screen_projection const projection; - ImDrawList *drawlist = ImGui::GetBackgroundDrawList(); + ImDrawList *drawlist = ImGui::GetBackgroundDrawList(ImGui::GetMainViewport()); auto const drawpath = [&](segment_data const &Path, ImU32 const Color) { auto previous{bezier{Path}.point(0.0)}; for (int i = 1; i <= 24; ++i) diff --git a/application/editormodetrackux.cpp b/application/editormodetrackux.cpp index 0de31ee4..f9c523cc 100644 --- a/application/editormodetrackux.cpp +++ b/application/editormodetrackux.cpp @@ -173,7 +173,7 @@ void editor_mode::draw_track_hover() const screen_projection const projection; if (track != selected_track()) { - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; for (int i = 0; i < static_cast(track->m_paths.size()); ++i) { bezier const curve{track->m_paths[i]}; @@ -489,7 +489,7 @@ void editor_mode::draw_track_intent() const if (intent.what == kind::none || intent.what == kind::gizmo || io.WantCaptureMouse) return; screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; ImVec2 at; if (projection.project(intent.position, at)) { @@ -528,7 +528,7 @@ void editor_mode::draw_track_intent() const auto const velocity{editor_track::velocity(*track)}; details += velocity > 0.0 ? format(" V %.0f km/h", velocity) : std::string{}; } - auto *foreground{ImGui::GetForegroundDrawList()}; + auto *foreground{ImGui::GetForegroundDrawList(ImGui::GetMainViewport())}; auto const actionsize{ImGui::CalcTextSize(intent.action.c_str())}; auto const detailsize{details.empty() ? ImVec2(0.0f, 0.0f) : ImGui::CalcTextSize(details.c_str())}; ImVec2 const size{std::max(actionsize.x, detailsize.x), actionsize.y + (details.empty() ? 0.0f : detailsize.y + 4.0f)}; @@ -1074,7 +1074,7 @@ void editor_mode::draw_track_spread() const if (m_intent.what != track_intent::kind::spread || m_spread.from == nullptr) return; screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; auto const removing{in_track_set(m_spread.from)}; auto const colour{removing ? IM_COL32(255, 90, 70, 220) : IM_COL32(90, 220, 255, 220)}; for (auto const *track : m_spread.preview) @@ -1099,7 +1099,7 @@ void editor_mode::draw_track_spread() const void editor_mode::draw_track_set() const { screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; if (m_track_box.active) { auto const &io{ImGui::GetIO()}; diff --git a/application/editormodeturntable.cpp b/application/editormodeturntable.cpp index f92b1b15..4cd20a8f 100644 --- a/application/editormodeturntable.cpp +++ b/application/editormodeturntable.cpp @@ -180,7 +180,7 @@ void label(screen_projection const &Projection, glm::dvec3 const &Point, std::st ImVec2 at; if (false == Projection.project(Point, at)) return; - auto *drawlist{ImGui::GetForegroundDrawList()}; + auto *drawlist{ImGui::GetForegroundDrawList(ImGui::GetMainViewport())}; auto const size{ImGui::CalcTextSize(Text.c_str())}; drawlist->AddRectFilled(ImVec2(at.x + 8.f, at.y - 4.f), ImVec2(at.x + 16.f + size.x, at.y + size.y + 4.f), IM_COL32(0, 0, 0, 170), 4.f); drawlist->AddText(ImVec2(at.x + 12.f, at.y), IM_COL32(255, 255, 255, 235), Text.c_str()); @@ -946,7 +946,7 @@ void editor_mode::draw_turntable_overlay() const using kind = track_intent::kind; auto const &tool{m_turntable}; screen_projection const projection; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; auto const camera{glm::dvec3{Global.pCamera.Pos}}; for (auto *track : simulation::Paths.sequence()) { diff --git a/application/editormodevehicle.cpp b/application/editormodevehicle.cpp index 4abc7ce2..58562caa 100644 --- a/application/editormodevehicle.cpp +++ b/application/editormodevehicle.cpp @@ -298,7 +298,7 @@ void editor_mode::draw_vehicle_marker() const ImVec2 screen; if (false == projection.project(tool.point, screen)) return; - auto *drawlist{ImGui::GetBackgroundDrawList()}; + auto *drawlist{ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())}; auto const colour{IM_COL32(255, 220, 60, 235)}; drawlist->AddCircle(screen, 9.0f, colour, 16, 2.5f); if (tool.track->m_editorremoved || tool.track->m_paths.empty()) diff --git a/application/uilayer.cpp b/application/uilayer.cpp index 621ece2e..4f949054 100644 --- a/application/uilayer.cpp +++ b/application/uilayer.cpp @@ -23,6 +23,7 @@ http://mozilla.org/MPL/2.0/. #include "imgui/imgui_impl_glfw.h" GLFWwindow *ui_layer::m_window{nullptr}; +GLFWwindow *ui_layer::m_keywindow{nullptr}; ImGuiIO *ui_layer::m_imguiio{nullptr}; GLint ui_layer::m_textureunit{GL_TEXTURE0}; bool ui_layer::m_cursorvisible; @@ -108,7 +109,7 @@ ui_layer::~ui_layer() {} bool ui_layer::key_callback(int key, int scancode, int action, int mods) { - ImGui_ImplGlfw_KeyCallback(m_window, key, scancode, action, mods); + ImGui_ImplGlfw_KeyCallback(m_keywindow != nullptr ? m_keywindow : m_window, key, scancode, action, mods); return m_imguiio->WantCaptureKeyboard; } @@ -152,6 +153,27 @@ void ui_layer::focus_callback(int focused) ImGui_ImplGlfw_WindowFocusCallback(m_window, focused); } +void ui_layer::viewport_key_callback(GLFWwindow *Window, int key, int scancode, int action, int mods) +{ + // imgui gets the key with the window it came from (the state of modifiers is read from it), the simulator gets it unless imgui takes it + m_keywindow = Window; + Application.on_key(key, scancode, action, mods); + m_keywindow = nullptr; +} + +namespace +{ +// window creation of the glfw backend, wrapped to give the new windows the key callback of the simulator +void (*imgui_create_window)(ImGuiViewport *Viewport){nullptr}; + +void create_viewport_window(ImGuiViewport *Viewport) +{ + imgui_create_window(Viewport); + if (Viewport->PlatformHandle != nullptr) + glfwSetKeyCallback(static_cast(Viewport->PlatformHandle), ui_layer::viewport_key_callback); +} +} // namespace + void ui_layer::imgui_style() { // palette shared with the MaSzyna starter: flat dark panels, thin borders, green accents @@ -341,6 +363,20 @@ bool ui_layer::init(GLFWwindow *Window) return false; } + // panels can be docked together, and dragged out of the simulator window into windows of their own (e.g. on another monitor) + // when both backends can do it. glfw can't place windows under wayland. both flags have to be set before the first frame + m_imguiio->ConfigFlags |= ImGuiConfigFlags_DockingEnable; + auto const viewportsupport{(m_imguiio->BackendFlags & ImGuiBackendFlags_PlatformHasViewports) && (m_imguiio->BackendFlags & ImGuiBackendFlags_RendererHasViewports) && + glfwGetPlatform() != GLFW_PLATFORM_WAYLAND}; + if (Global.ui_viewports && viewportsupport) + { + m_imguiio->ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; + auto &platformio{ImGui::GetPlatformIO()}; + imgui_create_window = platformio.Platform_CreateWindow; + platformio.Platform_CreateWindow = create_viewport_window; + } + WriteLog(std::string("ui: panels in separate windows ") + ((m_imguiio->ConfigFlags & ImGuiConfigFlags_ViewportsEnable) ? "enabled" : (viewportsupport ? "disabled in settings" : "not supported here"))); + return true; } @@ -440,6 +476,15 @@ void ui_layer::render_internal() { ImGui::Render(); GfxRenderer->GetImguiRenderer()->Render(); + + if (m_imguiio->ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + // panels outside of the main window are drawn in their own windows, whose gl contexts are shared with the main one + auto *context{glfwGetCurrentContext()}; + ImGui::UpdatePlatformWindows(); + ImGui::RenderPlatformWindowsDefault(); + glfwMakeContextCurrent(context); + } } void ui_layer::begin_ui_frame() @@ -670,5 +715,5 @@ void ui_layer::render_background() ImVec2 end_position(start_position.x + image_size.x, start_position.y + image_size.y); // obrazek jest odwrócony w pionie – odwracamy UV - ImGui::GetBackgroundDrawList()->AddImage((ImTextureID)(intptr_t)(tex.get_id()), start_position, end_position, ImVec2(0, 1), ImVec2(1, 0)); + ImGui::GetBackgroundDrawList(ImGui::GetMainViewport())->AddImage((ImTextureID)(intptr_t)(tex.get_id()), start_position, end_position, ImVec2(0, 1), ImVec2(1, 0)); } diff --git a/application/uilayer.h b/application/uilayer.h index 139664c9..975c1c77 100644 --- a/application/uilayer.h +++ b/application/uilayer.h @@ -122,6 +122,8 @@ public: static void cursor_pos_callback(double x, double y); static void cursor_enter_callback(int entered); static void focus_callback(int focused); + // key presses in windows of the ui outside of the main window, passed on to the simulator like those of the main window + static void viewport_key_callback(GLFWwindow *Window, int key, int scancode, int action, int mods); static ImFont *font_default; static ImFont *font_mono; @@ -130,6 +132,7 @@ public: protected: // members static GLFWwindow *m_window; + static GLFWwindow *m_keywindow; // window of the key event being handled static ImGuiIO *m_imguiio; static bool m_cursorvisible; diff --git a/editor/editorOrthophoto.cpp b/editor/editorOrthophoto.cpp index cee41d42..f9374261 100644 --- a/editor/editorOrthophoto.cpp +++ b/editor/editorOrthophoto.cpp @@ -1338,7 +1338,7 @@ void editor_orthophoto::draw(glm::mat4 const &ViewProjection, glm::dvec3 const & if (!m_enabled || m_config.in_scene || m_config.opacity <= 0.0f || ScreenWidth <= 0.0f || ScreenHeight <= 0.0f) return; - ImDrawList *drawlist = ImGui::GetBackgroundDrawList(); + ImDrawList *drawlist = ImGui::GetBackgroundDrawList(ImGui::GetMainViewport()); // without vertex offset support in the backend the whole list has to fit 16-bit indices std::size_t const vertexbudget = (ImGui::GetIO().BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ? vertex_budget * 8 : vertex_budget; ImU32 const color = IM_COL32(255, 255, 255, static_cast(m_config.opacity * 255.0f + 0.5f)); diff --git a/imgui/imgui_impl_glfw.cpp b/imgui/imgui_impl_glfw.cpp index a3d54549..35040b5d 100644 --- a/imgui/imgui_impl_glfw.cpp +++ b/imgui/imgui_impl_glfw.cpp @@ -181,6 +181,7 @@ struct ImGui_ImplGlfw_Data bool MouseIgnoreButtonUpWaitForFocusLoss; bool MouseIgnoreButtonUp; ImVec2 LastValidMousePos; + ImVec2 MainWindowOrigin; // MaSzyna: desktop position of the main window, see ImGui_ImplGlfw_UpdateMainWindowOrigin() GLFWwindow* KeyOwnerWindows[GLFW_KEY_LAST]; bool InstalledCallbacks; bool CallbacksChainForAllWindows; @@ -219,6 +220,7 @@ static ImGui_ImplGlfw_Data* ImGui_ImplGlfw_GetBackendData() // Forward Declarations static void ImGui_ImplGlfw_UpdateMonitors(); static void ImGui_ImplGlfw_InitMultiViewportSupport(); +static void ImGui_ImplGlfw_UpdateMainWindowOrigin(); static void ImGui_ImplGlfw_ShutdownMultiViewportSupport(); // Functions @@ -483,8 +485,8 @@ void ImGui_ImplGlfw_CursorPosCallback(GLFWwindow* window, double x, double y) { int window_x, window_y; glfwGetWindowPos(window, &window_x, &window_y); - x += window_x; - y += window_y; + x += window_x - bd->MainWindowOrigin.x; + y += window_y - bd->MainWindowOrigin.y; } io.AddMousePosEvent((float)x, (float)y); bd->LastValidMousePos = ImVec2((float)x, (float)y); @@ -802,8 +804,8 @@ static void ImGui_ImplGlfw_UpdateMouseData() // 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) int window_x, window_y; glfwGetWindowPos(window, &window_x, &window_y); - mouse_x += window_x; - mouse_y += window_y; + mouse_x += window_x - bd->MainWindowOrigin.x; + mouse_y += window_y - bd->MainWindowOrigin.y; } bd->LastValidMousePos = ImVec2((float)mouse_x, (float)mouse_y); io.AddMousePosEvent((float)mouse_x, (float)mouse_y); @@ -919,6 +921,7 @@ static void ImGui_ImplGlfw_UpdateGamepads() static void ImGui_ImplGlfw_UpdateMonitors() { + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); int monitors_count = 0; @@ -954,6 +957,9 @@ static void ImGui_ImplGlfw_UpdateMonitors() continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902. monitor.DpiScale = x_scale; #endif + // MaSzyna: monitors in imgui space as well + monitor.MainPos = ImVec2(monitor.MainPos.x - bd->MainWindowOrigin.x, monitor.MainPos.y - bd->MainWindowOrigin.y); + monitor.WorkPos = ImVec2(monitor.WorkPos.x - bd->MainWindowOrigin.x, monitor.WorkPos.y - bd->MainWindowOrigin.y); monitor.PlatformHandle = (void*)glfw_monitors[n]; // [...] GLFW doc states: "guaranteed to be valid only until the monitor configuration changes" platform_io.Monitors.push_back(monitor); } @@ -973,6 +979,7 @@ void ImGui_ImplGlfw_NewFrame() io.DisplaySize = ImVec2((float)w, (float)h); if (w > 0 && h > 0) io.DisplayFramebufferScale = ImVec2((float)display_w / (float)w, (float)display_h / (float)h); + ImGui_ImplGlfw_UpdateMainWindowOrigin(); ImGui_ImplGlfw_UpdateMonitors(); // Setup time step @@ -1148,7 +1155,7 @@ static void ImGui_ImplGlfw_CreateWindow(ImGuiViewport* viewport) #elif defined(__APPLE__) viewport->PlatformHandleRaw = (void*)glfwGetCocoaWindow(vd->Window); #endif - glfwSetWindowPos(vd->Window, (int)viewport->Pos.x, (int)viewport->Pos.y); + glfwSetWindowPos(vd->Window, (int)(viewport->Pos.x + bd->MainWindowOrigin.x), (int)(viewport->Pos.y + bd->MainWindowOrigin.y)); // Install GLFW callbacks for secondary viewports glfwSetWindowFocusCallback(vd->Window, ImGui_ImplGlfw_WindowFocusCallback); @@ -1234,17 +1241,40 @@ static void ImGui_ImplGlfw_ShowWindow(ImGuiViewport* viewport) static ImVec2 ImGui_ImplGlfw_GetWindowPos(ImGuiViewport* viewport) { + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; int x = 0, y = 0; glfwGetWindowPos(vd->Window, &x, &y); - return ImVec2((float)x, (float)y); + return ImVec2((float)x - bd->MainWindowOrigin.x, (float)y - bd->MainWindowOrigin.y); } static void ImGui_ImplGlfw_SetWindowPos(ImGuiViewport* viewport, ImVec2 pos) { + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); ImGui_ImplGlfw_ViewportData* vd = (ImGui_ImplGlfw_ViewportData*)viewport->PlatformUserData; vd->IgnoreWindowPosEventFrame = ImGui::GetFrameCount(); - glfwSetWindowPos(vd->Window, (int)pos.x, (int)pos.y); + glfwSetWindowPos(vd->Window, (int)(pos.x + bd->MainWindowOrigin.x), (int)(pos.y + bd->MainWindowOrigin.y)); +} + +// MaSzyna: with multi-viewports imgui positions are given relative to the main window of the simulator instead of the desktop, +// so the main viewport stays at (0,0) as it was without them: the simulator draws its overlays and reads the mouse in the +// coordinates of its window. When the main window moves, the windows of the other viewports are read again in the new space. +static void ImGui_ImplGlfw_UpdateMainWindowOrigin() +{ + ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData(); + ImVec2 origin(0.0f, 0.0f); + if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_ViewportsEnable) + { + int x = 0, y = 0; + glfwGetWindowPos(bd->Window, &x, &y); + origin = ImVec2((float)x, (float)y); + } + if (origin.x == bd->MainWindowOrigin.x && origin.y == bd->MainWindowOrigin.y) + return; + bd->MainWindowOrigin = origin; + ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO(); + for (int i = 1; i < platform_io.Viewports.Size; i++) + platform_io.Viewports[i]->PlatformRequestMove = true; } static ImVec2 ImGui_ImplGlfw_GetWindowSize(ImGuiViewport* viewport) diff --git a/utilities/Globals.cpp b/utilities/Globals.cpp index 2cf5235c..b4f2e14b 100644 --- a/utilities/Globals.cpp +++ b/utilities/Globals.cpp @@ -784,6 +784,12 @@ bool global_settings::ConfigParseUI(cParser& Parser, const std::string& token) return true; } + if (token == "ui.viewports") + { + ParseOne(Parser, ui_viewports, 1); + return true; + } + if (token == "gui.defaultwindows") { ParseOne(Parser, gui_defaultwindows, 1); @@ -1670,6 +1676,7 @@ global_settings::export_as_text( std::ostream &Output ) const { << UITextColor.g * 255 << " " << UITextColor.b * 255 << "\n"; export_as_text( Output, "ui.bg.opacity", UIBgOpacity ); + export_as_text( Output, "ui.viewports", ui_viewports ); export_as_text( Output, "input.gamepad", InputGamepad ); #ifdef WITH_UART if( uart_conf.enable ) { diff --git a/utilities/Globals.h b/utilities/Globals.h index f65fbc2c..08707d8c 100644 --- a/utilities/Globals.h +++ b/utilities/Globals.h @@ -306,6 +306,7 @@ struct global_settings { float ui_fontsize = 13.0f; float ui_scale = 1.0f; + bool ui_viewports = true; // panels of the ui can be dragged out of the simulator window, into windows of their own float map_highlight_distance = 3000.0f;