From 95d4581da2494df330c1a037b8679153591c0d52 Mon Sep 17 00:00:00 2001 From: maj00r Date: Thu, 8 Oct 2026 22:00:04 +0200 Subject: [PATCH] pan ortho view with middle mouse --- application/editormode.cpp | 46 ++++++++++++++++++++++++++++++++- application/editormode.h | 4 +++ application/editormodetrack.cpp | 2 ++ lang/editor_pl.po | 15 +++++++++++ 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/application/editormode.cpp b/application/editormode.cpp index 1ad54751..d833fdf5 100644 --- a/application/editormode.cpp +++ b/application/editormode.cpp @@ -30,6 +30,7 @@ extern char **environ; #include "editor/editorGeometry.hpp" #include "utilities/translation.h" #include "utilities/Globals.h" +#include "utilities/glmHelpers.h" #include "simulation/simulation.h" #include "simulation/simulationtime.h" #include "simulation/simulationenvironment.h" @@ -1212,6 +1213,8 @@ bool editor_mode::update() m_input.mouse.button(GLFW_MOUSE_BUTTON_RIGHT, GLFW_RELEASE); Application.set_cursor(GLFW_CURSOR_NORMAL); } + if (m_ortho_pan && !ImGui::GetIO().MouseDown[2]) + ortho_pan_stop(); // same for the left button (brush / sculpt / click placement). the UI filter in the application // uses io.WantCaptureMouse from the previous frame, so a press on a panel the cursor has just @@ -3631,11 +3634,15 @@ void editor_mode::render_gizmo_options() { if (ImGui::Button(Global.EditorOrtho ? "3D view (O)" : "Top view, orthographic (O)")) toggle_ortho(); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("%s", Global.EditorOrtho ? STR_C("Wheel zooms. Hold the wheel and drag to pan.") : STR_C("Top-down orthographic view")); if (Global.EditorOrtho) { ImGui::SameLine(); ImGui::SetNextItemWidth(120.0f); - ImGui::SliderFloat(STR_C("Extent (m), wheel"), &Global.EditorOrthoExtent, 5.0f, 5000.0f, "%.0f", 3.0f); + ImGui::SliderFloat(STR_C("Extent (m), wheel / MMB pan"), &Global.EditorOrthoExtent, 5.0f, 5000.0f, "%.0f", 3.0f); + if (ImGui::IsItemHovered()) + ImGui::SetTooltip("%s", STR_C("Wheel zooms. Hold the wheel and drag to pan.")); } ImGui::Checkbox(STR_C("Enabled"), &m_gizmo_enabled); if (!m_gizmo_enabled) @@ -3938,9 +3945,32 @@ void editor_mode::toggle_ortho() else { Camera.Angle.x = m_ortho_pitch; + ortho_pan_stop(); } } +void editor_mode::ortho_pan_to(double const Horizontal, double const Vertical) +{ + auto const &io{ImGui::GetIO()}; + if (io.DisplaySize.y <= 0.0f) + return; + auto const dx{Horizontal - m_ortho_pan_cursor.x}; + auto const dy{Vertical - m_ortho_pan_cursor.y}; + m_ortho_pan_cursor = {Horizontal, Vertical}; + auto const scale{2.0 * static_cast(Global.EditorOrthoExtent) / static_cast(io.DisplaySize.y)}; + auto const world{RotateY(glm::dvec3{dx * scale, 0.0, dy * scale}, static_cast(Camera.Angle.y))}; + Camera.Pos.x -= world.x; + Camera.Pos.z -= world.z; + Camera.Velocity = {}; + m_focus_active = false; + Global.pCamera = Camera; +} + +void editor_mode::ortho_pan_stop() +{ + m_ortho_pan = false; +} + void editor_mode::on_scroll(double const Xoffset, double const Yoffset) { if (false == Global.EditorOrtho || ImGui::GetIO().WantCaptureMouse) @@ -4367,6 +4397,8 @@ void editor_mode::on_key(int const Key, int const Scancode, int const Action, in void editor_mode::on_cursor_pos(double const Horizontal, double const Vertical) { + if (m_ortho_pan) + ortho_pan_to(Horizontal, Vertical); // object transforms are handled by the gizmo now; here we only forward the cursor to the // mouse input, which rotates the camera while the right mouse button is held (panning mode) m_input.mouse.position(Horizontal, Vertical); @@ -4582,6 +4614,18 @@ void editor_mode::on_mouse_button(int const Button, int const Action, int const // game-engine style look: hide & grab the cursor while flying, restore it on release Application.set_cursor(is_press(Action) ? GLFW_CURSOR_DISABLED : GLFW_CURSOR_NORMAL); } + else if (Button == GLFW_MOUSE_BUTTON_MIDDLE && Global.EditorOrtho) + { + if (is_press(Action)) + { + m_ortho_pan = true; + m_ortho_pan_cursor = m_input.mouse.position(); + m_focus_active = false; + Camera.Velocity = {}; + } + else if (is_release(Action)) + ortho_pan_stop(); + } m_input.mouse.button(Button, Action); } diff --git a/application/editormode.h b/application/editormode.h index 8e459bdc..3d256a91 100644 --- a/application/editormode.h +++ b/application/editormode.h @@ -209,6 +209,10 @@ class editor_mode : public application_mode, private editor_track::observer static bool m_settings_open; double m_ortho_pitch{0.0}; + bool m_ortho_pan{false}; + glm::dvec2 m_ortho_pan_cursor{0.0}; + void ortho_pan_to(double const Horizontal, double const Vertical); + void ortho_pan_stop(); // camera fly-mode (right mouse button held); used to flush motion when it's released command_relay m_camera_relay; bool m_camera_flying{false}; diff --git a/application/editormodetrack.cpp b/application/editormodetrack.cpp index b59ff0f7..af0d4162 100644 --- a/application/editormodetrack.cpp +++ b/application/editormodetrack.cpp @@ -3584,6 +3584,8 @@ std::vector editor_mode::track_key_hints(bool const All) hints.push_back({"Ctrl", format("gizmo snaps by %.2f m", m_gizmo_snap)}); hints.push_back({"K", "split the path under the cursor"}); hints.push_back({"O", "top view"}); + if (Global.EditorOrtho) + hints.push_back({"Hold the wheel", "pans the view"}); hints.push_back({"Ctrl+Z", "undo"}); hints.push_back({"Ctrl+Y", "redo"}); hints.push_back({"L T G C B P V J I", "modes: lay, switch, straight, curve, objects, profile, speed, joints, infra"}); diff --git a/lang/editor_pl.po b/lang/editor_pl.po index 36a55c79..c27ec30d 100644 --- a/lang/editor_pl.po +++ b/lang/editor_pl.po @@ -4243,6 +4243,21 @@ msgstr "Zaznacz model, z którego ma powstać tablica" msgid "Extent (m), wheel" msgstr "Zasięg (m), kółko" +msgid "Extent (m), wheel / MMB pan" +msgstr "Zasięg (m), kółko / przesuwanie kółkiem" + +msgid "Wheel zooms. Hold the wheel and drag to pan." +msgstr "Kółko przybliża. Wciśnij kółko i przeciągnij, żeby przesunąć widok." + +msgid "Top-down orthographic view" +msgstr "Widok z góry, rzut prostokątny" + +msgid "Hold the wheel" +msgstr "Przytrzymaj kółko" + +msgid "pans the view" +msgstr "przesuwa widok" + msgid "Enabled" msgstr "Włączone"