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

Code before:
						bool local_coords = (spatial_editor->are_local_coords_enabled() && _edit.plane != TRANSFORM_VIEW);

						if (_edit.snap || spatial_editor->is_snap_enabled()) {
							snap = spatial_editor->get_scale_snap() / 100;
						}
						Vector3 motion_snapped = motion;
						motion_snapped.snap(Vector3(snap, snap, snap));
						// This might not be necessary anymore after issue #288 is solved (in 4.0?).
						set_message(TTR("Scaling: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
								String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");

						List<Node *> &selection = editor_selection->get_selected_node_list();
						for (Node *E : selection) {
							Node3D *sp = Object::cast_to<Node3D>(E);
							if (!sp) {
								continue;
							}

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

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

							if (se->gizmo.is_valid()) {
								for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
									Transform3D xform = GE.value;
									Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original * xform, xform, motion, snap, local_coords);
									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(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords);
								_transform_gizmo_apply(se->sp, new_xform, local_coords);
							}
						}

						spatial_editor->update_transform_gizmo();
						surface->update();

					} break;

					case TRANSFORM_TRANSLATE: {
						Vector3 motion_mask;
						Plane plane;
						bool plane_mv = false;

Review comment (suggestion):
Currently SubGizmo is forcing orthogonal, but I'm wondering how to make this work better.
At least it's independent of Node3D's RotationMode, but if you want to manage it on a per-SubGizmo make orthogonal, we need to make the SubGizmo store more info than just Transform3D.

For now, it is only the manipulation of bones in Skeleton3DGizmo that is being transformed using SubGizmo, so I don't see a problem with it, but if there is a suggestion in the future, I think it should be resolved.

Code after:
						motion_snapped.snap(Vector3(snap, snap, snap));
						// This might not be necessary anymore after issue #288 is solved (in 4.0?).
						set_message(TTR("Scaling: ") + "(" + String::num(motion_snapped.x, snap_step_decimals) + ", " +
								String::num(motion_snapped.y, snap_step_decimals) + ", " + String::num(motion_snapped.z, snap_step_decimals) + ")");
						motion = _edit.original.basis.inverse().xform(motion);

						List<Node *> &selection = editor_selection->get_selected_node_list();
						for (Node *E : selection) {
							Node3D *sp = Object::cast_to<Node3D>(E);
							if (!sp) {
								continue;
							}

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

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

							if (se->gizmo.is_valid()) {
								for (KeyValue<int, Transform3D> &GE : se->subgizmos) {
									Transform3D xform = GE.value;
									Transform3D new_xform = _compute_transform(TRANSFORM_SCALE, se->original * xform, xform, motion, snap, local_coords, true); // 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(TRANSFORM_SCALE, se->original, se->original_local, motion, snap, local_coords, sp->get_rotation_edit_mode() != Node3D::ROTATION_EDIT_MODE_BASIS);
								_transform_gizmo_apply(se->sp, new_xform, local_coords);
							}
						}

						spatial_editor->update_transform_gizmo();
						surface->update();

					} break;

					case TRANSFORM_TRANSLATE: {
						Vector3 motion_mask;
						Plane plane;
						bool plane_mv = false;

						switch (_edit.plane) {
							case TRANSFORM_VIEW:
								plane = Plane(_get_camera_normal(), _edit.center);
								break;