diff --git a/.gitignore b/.gitignore index 426e149..53a9d78 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,5 @@ profile.json CMakeUserPresets.json *.sublime-workspace .idea/ + +.vs/ diff --git a/src/core/Core/Application.cpp b/src/core/Core/Application.cpp index 7dc1254..c26412d 100644 --- a/src/core/Core/Application.cpp +++ b/src/core/Core/Application.cpp @@ -136,7 +136,40 @@ ExitStatus App::Application::run() { const ImVec2 canvas_p0 = ImGui::GetCursorScreenPos(); const ImVec2 canvas_sz = ImGui::GetContentRegionAvail(); const auto canvas_p1 = ImVec2(canvas_p0.x + canvas_sz.x, canvas_p0.y + canvas_sz.y); - const ImVec2 origin(canvas_p0.x + canvas_sz.x * 0.5f, canvas_p0.y + canvas_sz.y * 0.5f); + // --- PANNING IMPLEMENTATION BEGIN --- + static bool isPanning = false; + static ImVec2 lastMousePos = {0.0f, 0.0f}; + static ImVec2 originOffset = {0.0f, 0.0f}; + + // Get mouse position + ImVec2 mousePos = ImGui::GetMousePos(); + + // Detect click start only when cursor is inside the graphing area + if (ImGui::IsWindowHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { + isPanning = true; + lastMousePos = mousePos; + } + + // Stop panning when mouse released + if (ImGui::IsMouseReleased(ImGuiMouseButton_Left)) { + isPanning = false; + } + + // While dragging, update origin offset + if (isPanning && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { + ImVec2 delta = ImVec2(mousePos.x - lastMousePos.x, mousePos.y - lastMousePos.y); + originOffset.x += delta.x; + originOffset.y += delta.y; + lastMousePos = mousePos; + } + + // Apply offset to origin + const ImVec2 origin( + canvas_p0.x + canvas_sz.x * 0.5f + originOffset.x, + canvas_p0.y + canvas_sz.y * 0.5f + originOffset.y + ); + // --- PANNING IMPLEMENTATION END --- + float lineThickness = 6.0f; // --- Thin integer gridlines with adaptive spacing --- @@ -228,12 +261,13 @@ ExitStatus App::Application::run() { const double t_step = 0.02; for (t = t_min; t <= t_max; t += t_step) { - const double vx = expr_fx.value(); - const double vy = expr_gx.value(); - - - ImVec2 screen_pos(origin.x + static_cast(vx * zoom), - origin.y - static_cast(vy * zoom)); + const double vx = expr_fx.value(); + const double vy = expr_gx.value(); + // The 'origin' variable already includes the pan offset. + ImVec2 screen_pos( + origin.x + static_cast(vx * zoom), + origin.y - static_cast(vy * zoom) + ); points.push_back(screen_pos); } @@ -264,11 +298,11 @@ ExitStatus App::Application::run() { if (parser.compile(func_str, expression)) { // grid parameters - const double x_min = -canvas_sz.x / (2 * zoom); - const double x_max = canvas_sz.x / (2 * zoom); - const double y_min = -canvas_sz.y / (2 * zoom); - const double y_max = canvas_sz.y / (2 * zoom); - + const double x_min = (-canvas_sz.x * 0.5f - originOffset.x) / zoom; + const double x_max = ( canvas_sz.x * 0.5f - originOffset.x) / zoom; + const double y_min = (-canvas_sz.y * 0.5f + originOffset.y) / zoom; + const double y_max = ( canvas_sz.y * 0.5f + originOffset.y) / zoom; + // adaptive step size with performance limit const double step = std::max(0.025, 1.5 / zoom); const ImU32 inequality_color = IM_COL32(100, 150, 255, 180); @@ -346,10 +380,10 @@ ExitStatus App::Application::run() { if (compile_ok) { // grid parameters - const double x_min = -canvas_sz.x / (2 * zoom); - const double x_max = canvas_sz.x / (2 * zoom); - const double y_min = -canvas_sz.y / (2 * zoom); - const double y_max = canvas_sz.y / (2 * zoom); + const double x_min = (-canvas_sz.x * 0.5f - originOffset.x) / zoom; + const double x_max = ( canvas_sz.x * 0.5f - originOffset.x) / zoom; + const double y_min = (-canvas_sz.y * 0.5f + originOffset.y) / zoom; + const double y_max = ( canvas_sz.y * 0.5f + originOffset.y) / zoom; const double step = std::max(0.008, 1.0 / zoom); //dynamic step based on zoom level const ImU32 implicit_color = IM_COL32(64, 199, 128, 255); @@ -473,12 +507,20 @@ ExitStatus App::Application::run() { exprtk::parser parser; parser.compile(function, expression); - for (x = -canvas_sz.x / (2 * zoom); x < canvas_sz.x / (2 * zoom); x += 0.05) { - const double y = expression.value(); - - ImVec2 screen_pos(origin.x + x * zoom, origin.y - y * zoom); - points.push_back(screen_pos); - } + // Calculate the visible x-range in world-space, accounting for the pan + const float world_x_min = (-canvas_sz.x * 0.5f - originOffset.x) / zoom; + const float world_x_max = ( canvas_sz.x * 0.5f - originOffset.x) / zoom; + + // Evaluate the function across the correct visible world-range + for (x = world_x_min; x <= world_x_max; x += 0.05) { + const double y = expression.value(); + // The 'origin' variable already includes the pan offset. + ImVec2 screen_pos( + origin.x + static_cast(x * zoom), + origin.y - static_cast(y * zoom) + ); + points.push_back(screen_pos); + } draw_list->AddPolyline(points.data(), points.size(),