--- a/plugins/cube/cube.cpp +++ b/plugins/cube/cube.cpp @@ -422,6 +422,7 @@ timed_transition_t row_translation{animation.cube_animation}; timed_transition_t overview_row{animation.cube_animation}; timed_transition_t overview_mix{animation.cube_animation}; + timed_transition_t mouse_center_mix{animation.cube_animation}; void start_animation(int duration_limit_ms = -1) { @@ -548,6 +549,7 @@ void end_mouse_overview() { + mouse_center_mix.set(0, 0); if (mouse_overview_active) { mouse_overview_active = false; @@ -598,6 +600,7 @@ animation.cube_animation.rotation.set(0, 0); animation.cube_animation.zoom.set(1, 1); animation.cube_animation.ease_deformation.set(0, 0); + mouse_center_mix.set(0, 0); start_animation(); @@ -929,6 +932,7 @@ identity_z_offset + front_face_distance()); animation.cube_animation.zoom.set(1, 1); animation.cube_animation.ease_deformation.set(0, 0); + mouse_center_mix.set(0, 0); update_view_matrix(); render_node = std::make_shared(this); add_cube_render_node(); @@ -1162,6 +1166,7 @@ mouse_overview_active = false; return_to_rest = false; overview_mix.set(0, 0); + mouse_center_mix.set(0, 0); clear_fixed_workspace_overlay(); clear_unused_fixed_top_node(); release_cube_input(); @@ -1185,6 +1190,7 @@ identity_z_offset + front_face_distance()); animation.cube_animation.offset_y.restart_with_end(0); animation.cube_animation.ease_deformation.restart_with_end(0); + mouse_center_mix.restart_with_end(0); } /* Start moving to a workspace to the left/right using the keyboard */ @@ -1254,6 +1260,7 @@ end_vertical_transition(); end_mouse_overview(); return_to_rest = false; + mouse_center_mix.set(0, 1); if (mouse_overview && output->wset()->get_workspace_grid_size().height > 1) { workspace_animation_anchor.reset(); @@ -1382,7 +1389,10 @@ auto camera = glm::translate(glm::mat4(1.f), glm::vec3(0.f, 0.f, -distance)); auto rotation = glm::rotate(glm::mat4(1.f), pitch, glm::vec3(1, 0, 0)); - auto pivot = glm::translate(glm::mat4(1.f), glm::vec3(0, center, 0)); + // Frame the whole cube at its midpoint during mouse rotation, then + // return to the selected row on release. The pivot itself stays fixed. + const float frame_center = center * (1 - float(mouse_center_mix)); + auto pivot = glm::translate(glm::mat4(1.f), glm::vec3(0, frame_center, 0)); auto unpivot = glm::translate(glm::mat4(1.f), glm::vec3(0, -center, 0)); return camera * pivot * rotation * unpivot; } @@ -1399,12 +1409,9 @@ // Wheel zoom and the configured camera offset stay independent of fit. const float radius = cube_rotation_radius(); const float distance = radius + front_face_distance(); - const float rows = output->wset()->get_workspace_grid_size().height; - const float center = std::abs((rows - 1) / 2 - float(overview_row)); const float tangent = distance * distance - radius * radius; const float horizontal = animation.projection[0][0] * radius / std::sqrt(tangent); - const float vertical = animation.projection[1][1] * - (center * distance + radius * std::sqrt(tangent + center * center)) / tangent; + const float vertical = animation.projection[1][1] * radius / std::sqrt(tangent); return 0.8f / std::max({1.0f, horizontal, vertical}); } @@ -1422,7 +1429,7 @@ if (mouse_overview_active) { - // Fit every row while keeping the selected row centered. Scale + // Fit the centered stack independently of the selected row. Scale // the complete projected stack uniformly, preserving face shape. float fit = overview_fit(); float scale = 1 + float(overview_mix) * (fit - 1);