Repository: godotengine/godot
File: editor/plugins/node_3d_editor_plugin.cpp (C++)

Code before:
	if (!last_node_3d) {
		return;
	}

	last_basis = last_node_3d->get_global_basis();

	for (Node *E : selection) {
		Node3D *sp = Object::cast_to<Node3D>(E);
		bool is_relative = true;

		if (!sp) {
			continue;
		}

		Node3DEditorSelectedItem *se = editor_selection->get_node_editor_data<Node3DEditorSelectedItem>(sp);
		if (!se) {
			continue;
		}

		if (sp->has_meta("_edit_lock_")) {
			continue;
		}

		if (!local_coords || last_node_3d == sp) {
			is_relative = false;
		}

		if (se->gizmo.is_valid()) {
			for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
				Transform3D xform = GE.value;
				Transform3D new_xform = _compute_transform(_edit.mode, se->original * xform, xform, last_basis, p_motion, p_snap, local_coords, _edit.plane != TRANSFORM_VIEW, is_relative); // Force orthogonal with subgizmo.
				if (!local_coords) {
					new_xform = se->original.affine_inverse() * new_xform;
				}
				se->gizmo->set_subgizmo_transform(GE.key, new_xform);
			}
		} else {
			Transform3D new_xform = _compute_transform(_edit.mode, se->original, se->original_local, last_basis, p_motion, p_snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS && _edit.plane != TRANSFORM_VIEW, is_relative);
			_transform_gizmo_apply(se->sp, new_xform, local_coords);
		}
	}

	spatial_editor->update_transform_gizmo();
	surface->queue_redraw();
}

// Update the current transform operation in response to an input.
void Node3DEditorViewport::update_transform(bool p_shift) {
	Vector3 ray_pos = get_ray_pos(_edit.mouse_pos);
	Vector3 ray = get_ray(_edit.mouse_pos);
	double snap = EDITOR_GET("interface/inspector/default_float_step");

Review comment (suggestion):
The relative option must be an additional option for local mode. Can you add a button at the top of the viewport that is only visible when local mode is enabled?

It could be a pull-down like in Blender, but since there are currently only two states, one button indicating indivisual or relative local would be sufficient for now. I assume a `"DistractionFree"` icon could be substituted to indicate that indivisual local mode is enabled.

![image](https://github.com/user-attachments/assets/24a8375e-e78a-4bf1-b609-670194ac3f96)



Code after:
	double snap = EDITOR_GET("interface/inspector/default_float_step");
	int snap_step_decimals = Math::range_step_decimals(snap);

	switch (_edit.mode) {
		case TRANSFORM_SCALE: {
			Vector3 motion_mask;
			Plane plane;
			bool plane_mv = false;

			switch (_edit.plane) {
				case TRANSFORM_VIEW:
					motion_mask = Vector3(0, 0, 0);
					plane = Plane(_get_camera_normal(), _edit.center);
					break;
				case TRANSFORM_X_AXIS:
					motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(0).normalized();
					plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
					break;
				case TRANSFORM_Y_AXIS:
					motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(1).normalized();
					plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
					break;
				case TRANSFORM_Z_AXIS:
					motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(2).normalized();
					plane = Plane(motion_mask.cross(motion_mask.cross(_get_camera_normal())).normalized(), _edit.center);
					break;
				case TRANSFORM_YZ:
					motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(2).normalized() + spatial_editor->get_gizmo_transform().basis.get_column(1).normalized();
					plane = Plane(spatial_editor->get_gizmo_transform().basis.get_column(0).normalized(), _edit.center);
					plane_mv = true;
					break;
				case TRANSFORM_XZ:
					motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(2).normalized() + spatial_editor->get_gizmo_transform().basis.get_column(0).normalized();
					plane = Plane(spatial_editor->get_gizmo_transform().basis.get_column(1).normalized(), _edit.center);
					plane_mv = true;
					break;
				case TRANSFORM_XY:
					motion_mask = spatial_editor->get_gizmo_transform().basis.get_column(0).normalized() + spatial_editor->get_gizmo_transform().basis.get_column(1).normalized();
					plane = Plane(spatial_editor->get_gizmo_transform().basis.get_column(2).normalized(), _edit.center);
					plane_mv = true;
					break;
			}

			Vector3 intersection;
			if (!plane.intersects_ray(ray_pos, ray, &intersection)) {
				break;
			}

			Vector3 click;
			if (!plane.intersects_ray(_edit.click_ray_pos, _edit.click_ray, &click)) {
				break;