Repository: godotengine/godot
File: editor/scene/3d/node_3d_editor_plugin.cpp (C++)

Code before:

		} else if (m->get_button_mask().has_flag(MouseButtonMask::LEFT)) {
			NavigationMode change_nav_from_shortcut = _get_nav_mode_from_shortcut_check(NAVIGATION_LEFT_MOUSE, shortcut_check_sets, false);
			if (change_nav_from_shortcut != NAVIGATION_NONE) {
				nav_mode = change_nav_from_shortcut;
			} else {
				const bool movement_threshold_passed = _edit.original_mouse_pos.distance_to(_edit.mouse_pos) > 8 * EDSCALE;

				if ((selection_in_progress || clicked_wants_append) && movement_threshold_passed && clicked.is_valid()) {
					cursor.region_select = true;
					cursor.region_begin = _edit.original_mouse_pos;
					clicked = ObjectID();
				}

				if (cursor.region_select) {
					cursor.region_end = m->get_position();
					surface->queue_redraw();
					return;
				}

				if (clicked.is_valid() && movement_threshold_passed && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE)) {
					bool is_select_mode = (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT);
					bool is_clicked_selected = editor_selection->is_selected(ObjectDB::get_instance<Node>(clicked));

					if (is_select_mode || is_clicked_selected) {
						_compute_edit(_edit.original_mouse_pos);
						clicked = ObjectID();
						if (_edit.mode != TRANSFORM_ROTATE) {
							_edit.mode = TRANSFORM_TRANSLATE;
						}
					}
				}

				if (_edit.mode == TRANSFORM_NONE || _edit.numeric_input != 0 || _edit.numeric_next_decimal != 0) {
					return;
				}

				if (!selection_in_progress) {
					update_transform(_get_key_modifier(m) == Key::SHIFT);
				}
			}
		} else if (m->get_button_mask().has_flag(MouseButtonMask::RIGHT) || freelook_active) {
			NavigationMode change_nav_from_shortcut = _get_nav_mode_from_shortcut_check(NAVIGATION_RIGHT_MOUSE, shortcut_check_sets, false);
			if (m->get_button_mask().has_flag(MouseButtonMask::RIGHT) && change_nav_from_shortcut != NAVIGATION_NONE) {
				nav_mode = change_nav_from_shortcut;
			} else if (freelook_active) {
				nav_mode = NAVIGATION_LOOK;
			} else if (orthogonal) {
				nav_mode = NAVIGATION_PAN;
			}


Review comment (bug):
This is called even if the rotation already started, which leads to a wrong undo/redo history. Steps to reproduce:
1. make sure you are in select mode
2. select object
3. hold control and drag object
4. undo: the rotation is not reset correctly when undoing

As far as I understand, this is why the undo/redo history has a wrong value for undoing:
- The rotation is started initially within `_sinput()` (to be exact: line 2076)
- Then after moving the mouse more than the threshold, it is started again here in line 2242. At this point the object is already rotated a bit, so calling `_compute_edit()` again will store the already rotated transform as the "initial" transform, overriding the correct one
- When the transform is finished, the undo/redo is registered with the wrong initial transform value


Code after:

		} else if (m->get_button_mask().has_flag(MouseButtonMask::LEFT)) {
			NavigationMode change_nav_from_shortcut = _get_nav_mode_from_shortcut_check(NAVIGATION_LEFT_MOUSE, shortcut_check_sets, false);
			if (change_nav_from_shortcut != NAVIGATION_NONE) {
				nav_mode = change_nav_from_shortcut;
			} else {
				const bool movement_threshold_passed = _edit.original_mouse_pos.distance_to(_edit.mouse_pos) > 8 * EDSCALE;

				if ((selection_in_progress || clicked_wants_append) && movement_threshold_passed && clicked.is_valid()) {
					cursor.region_select = true;
					cursor.region_begin = _edit.original_mouse_pos;
					clicked = ObjectID();
				}

				if (cursor.region_select) {
					cursor.region_end = m->get_position();
					surface->queue_redraw();
					return;
				}

				if (clicked.is_valid() && movement_threshold_passed && (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE)) {
					bool is_select_mode = (spatial_editor->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT);
					bool is_clicked_selected = editor_selection->is_selected(ObjectDB::get_instance<Node>(clicked));

					if (_edit.mode == TRANSFORM_NONE && (is_select_mode || is_clicked_selected)) {
						_compute_edit(_edit.original_mouse_pos);
						clicked = ObjectID();
						_edit.mode = TRANSFORM_TRANSLATE;
					}
				}

				if (_edit.mode == TRANSFORM_NONE || _edit.numeric_input != 0 || _edit.numeric_next_decimal != 0) {
					return;
				}

				if (!selection_in_progress) {
					update_transform(_get_key_modifier(m) == Key::SHIFT);
				}
			}
		} else if (m->get_button_mask().has_flag(MouseButtonMask::RIGHT) || freelook_active) {
			NavigationMode change_nav_from_shortcut = _get_nav_mode_from_shortcut_check(NAVIGATION_RIGHT_MOUSE, shortcut_check_sets, false);
			if (m->get_button_mask().has_flag(MouseButtonMask::RIGHT) && change_nav_from_shortcut != NAVIGATION_NONE) {
				nav_mode = change_nav_from_shortcut;
			} else if (freelook_active) {
				nav_mode = NAVIGATION_LOOK;
			} else if (orthogonal) {
				nav_mode = NAVIGATION_PAN;
			}

		} else if (m->get_button_mask().has_flag(MouseButtonMask::MIDDLE)) {
			NavigationMode change_nav_from_shortcut = _get_nav_mode_from_shortcut_check(NAVIGATION_MIDDLE_MOUSE, shortcut_check_sets, false);