diff --git a/editor/editor_properties_vector.cpp b/editor/editor_properties_vector.cpp index 365cbc6ec87..a3327043358 100644 --- a/editor/editor_properties_vector.cpp +++ b/editor/editor_properties_vector.cpp @@ -130,9 +130,11 @@ void EditorPropertyVectorN::_notification(int p_what) { switch (p_what) { case NOTIFICATION_READY: { if (linked->is_visible()) { - const String key = vformat("%s:%s", get_edited_object()->get_class(), get_edited_property()); - linked->set_pressed_no_signal(EditorSettings::get_singleton()->get_project_metadata("linked_properties", key, true)); - _update_ratio(); + if (get_edited_object()) { + const String key = vformat("%s:%s", get_edited_object()->get_class(), get_edited_property()); + linked->set_pressed_no_signal(EditorSettings::get_singleton()->get_project_metadata("linked_properties", key, true)); + _update_ratio(); + } } } break; diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index b340dd976e0..6d31e196ead 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -47,6 +47,7 @@ #include "scene/3d/physics/physics_body_3d.h" #include "scene/gui/separator.h" #include "scene/gui/texture_rect.h" +#include "scene/property_utils.h" #include "scene/resources/3d/capsule_shape_3d.h" #include "scene/resources/skeleton_profile.h" #include "scene/resources/surface_tool.h" @@ -65,7 +66,7 @@ void BoneTransformEditor::create_editors() { // Position property. position_property = memnew(EditorPropertyVector3()); - position_property->setup(-10000, 10000, 0.001f, true); + position_property->setup(-10000, 10000, 0.001, true); position_property->set_label("Position"); position_property->set_selectable(false); position_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed)); @@ -74,7 +75,7 @@ void BoneTransformEditor::create_editors() { // Rotation property. rotation_property = memnew(EditorPropertyQuaternion()); - rotation_property->setup(-10000, 10000, 0.001f, true); + rotation_property->setup(-10000, 10000, 0.001, true); rotation_property->set_label("Rotation"); rotation_property->set_selectable(false); rotation_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed)); @@ -83,7 +84,7 @@ void BoneTransformEditor::create_editors() { // Scale property. scale_property = memnew(EditorPropertyVector3()); - scale_property->setup(-10000, 10000, 0.001f, true); + scale_property->setup(-10000, 10000, 0.001, true, true); scale_property->set_label("Scale"); scale_property->set_selectable(false); scale_property->connect("property_changed", callable_mp(this, &BoneTransformEditor::_value_changed)); @@ -97,7 +98,7 @@ void BoneTransformEditor::create_editors() { // Transform/Matrix property. rest_matrix = memnew(EditorPropertyTransform3D()); - rest_matrix->setup(-10000, 10000, 0.001f, true); + rest_matrix->setup(-10000, 10000, 0.001, true); rest_matrix->set_label("Transform"); rest_matrix->set_selectable(false); rest_section->get_vbox()->add_child(rest_matrix); @@ -122,6 +123,13 @@ void BoneTransformEditor::_value_changed(const String &p_property, const Variant undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS); undo_redo->add_undo_property(skeleton, p_property, skeleton->get(p_property)); undo_redo->add_do_property(skeleton, p_property, p_value); + + Skeleton3DEditor *se = Skeleton3DEditor::get_singleton(); + if (se) { + undo_redo->add_do_method(se, "update_joint_tree"); + undo_redo->add_undo_method(se, "update_joint_tree"); + } + undo_redo->commit_action(); } } @@ -189,26 +197,31 @@ void BoneTransformEditor::_update_properties() { if (split[2] == "enabled") { enabled_checkbox->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); enabled_checkbox->update_property(); + enabled_checkbox->update_editor_property_status(); enabled_checkbox->queue_redraw(); } if (split[2] == "position") { position_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); position_property->update_property(); + position_property->update_editor_property_status(); position_property->queue_redraw(); } if (split[2] == "rotation") { rotation_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); rotation_property->update_property(); + rotation_property->update_editor_property_status(); rotation_property->queue_redraw(); } if (split[2] == "scale") { scale_property->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); scale_property->update_property(); + scale_property->update_editor_property_status(); scale_property->queue_redraw(); } if (split[2] == "rest") { rest_matrix->set_read_only(E.usage & PROPERTY_USAGE_READ_ONLY); rest_matrix->update_property(); + rest_matrix->update_editor_property_status(); rest_matrix->queue_redraw(); } } @@ -232,6 +245,11 @@ void Skeleton3DEditor::set_bone_options_enabled(const bool p_bone_options_enable skeleton_options->get_popup()->set_item_disabled(SKELETON_OPTION_SELECTED_POSES_TO_RESTS, !p_bone_options_enabled); }; +void Skeleton3DEditor::_bind_methods() { + ClassDB::bind_method(D_METHOD("update_all"), &Skeleton3DEditor::update_all); + ClassDB::bind_method(D_METHOD("update_joint_tree"), &Skeleton3DEditor::update_joint_tree); +} + void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) { if (!skeleton) { return; @@ -294,6 +312,10 @@ void Skeleton3DEditor::reset_pose(const bool p_all_bones) { ur->add_undo_method(skeleton, "set_bone_pose_scale", selected_bone, skeleton->get_bone_pose_scale(selected_bone)); ur->add_do_method(skeleton, "reset_bone_pose", selected_bone); } + + ur->add_undo_method(this, "update_joint_tree"); + ur->add_do_method(this, "update_joint_tree"); + ur->commit_action(); } @@ -357,6 +379,10 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) { ur->add_do_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_pose(selected_bone)); ur->add_undo_method(skeleton, "set_bone_rest", selected_bone, skeleton->get_bone_rest(selected_bone)); } + + ur->add_undo_method(this, "update_joint_tree"); + ur->add_do_method(this, "update_joint_tree"); + ur->commit_action(); } @@ -620,9 +646,12 @@ void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_se } ur->add_undo_method(skeleton_node, "set_bone_parent", p_selected_boneidx, skeleton_node->get_bone_parent(p_selected_boneidx)); ur->add_do_method(skeleton_node, "set_bone_parent", p_selected_boneidx, p_target_boneidx); + + ur->add_undo_method(this, "update_joint_tree"); + ur->add_do_method(this, "update_joint_tree"); + skeleton_node->set_bone_parent(p_selected_boneidx, p_target_boneidx); - update_joint_tree(); ur->commit_action(); } @@ -655,6 +684,107 @@ void Skeleton3DEditor::_joint_tree_selection_changed() { void Skeleton3DEditor::_joint_tree_rmb_select(const Vector2 &p_pos, MouseButton p_button) { } +void Skeleton3DEditor::_joint_tree_button_clicked(Object *p_item, int p_column, int p_id, MouseButton p_button) { + if (!skeleton) { + return; + } + + TreeItem *tree_item = Object::cast_to(p_item); + if (tree_item) { + String tree_item_metadata = tree_item->get_metadata(0); + + String bone_enabled_property = tree_item_metadata + "/enabled"; + String bone_parent_property = tree_item_metadata + "/parent"; + String bone_name_property = tree_item_metadata + "/name"; + String bone_position_property = tree_item_metadata + "/position"; + String bone_rotation_property = tree_item_metadata + "/rotation"; + String bone_scale_property = tree_item_metadata + "/scale"; + String bone_rest_property = tree_item_metadata + "/rest"; + + Variant current_enabled = skeleton->get(bone_enabled_property); + Variant current_parent = skeleton->get(bone_parent_property); + Variant current_name = skeleton->get(bone_name_property); + Variant current_position = skeleton->get(bone_position_property); + Variant current_rotation = skeleton->get(bone_rotation_property); + Variant current_scale = skeleton->get(bone_scale_property); + Variant current_rest = skeleton->get(bone_rest_property); + + EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton(); + ur->create_action(TTR("Revert Bone")); + + bool can_revert_enabled = EditorPropertyRevert::can_property_revert(skeleton, bone_enabled_property, ¤t_enabled); + if (can_revert_enabled) { + bool is_valid = false; + Variant new_enabled = EditorPropertyRevert::get_property_revert_value(skeleton, bone_enabled_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_enabled_property, current_enabled); + ur->add_do_method(skeleton, "set", bone_enabled_property, new_enabled); + } + } + + bool can_revert_parent = EditorPropertyRevert::can_property_revert(skeleton, bone_parent_property, ¤t_parent); + if (can_revert_parent) { + bool is_valid = false; + Variant new_parent = EditorPropertyRevert::get_property_revert_value(skeleton, bone_parent_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_parent_property, current_parent); + ur->add_do_method(skeleton, "set", bone_parent_property, new_parent); + } + } + bool can_revert_name = EditorPropertyRevert::can_property_revert(skeleton, bone_name_property, ¤t_name); + if (can_revert_name) { + bool is_valid = false; + Variant new_name = EditorPropertyRevert::get_property_revert_value(skeleton, bone_name_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_name_property, current_name); + ur->add_do_method(skeleton, "set", bone_name_property, new_name); + } + } + bool can_revert_position = EditorPropertyRevert::can_property_revert(skeleton, bone_position_property, ¤t_position); + if (can_revert_position) { + bool is_valid = false; + Variant new_position = EditorPropertyRevert::get_property_revert_value(skeleton, bone_position_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_position_property, current_position); + ur->add_do_method(skeleton, "set", bone_position_property, new_position); + } + } + bool can_revert_rotation = EditorPropertyRevert::can_property_revert(skeleton, bone_rotation_property, ¤t_rotation); + if (can_revert_rotation) { + bool is_valid = false; + Variant new_rotation = EditorPropertyRevert::get_property_revert_value(skeleton, bone_rotation_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_rotation_property, current_rotation); + ur->add_do_method(skeleton, "set", bone_rotation_property, new_rotation); + } + } + bool can_revert_scale = EditorPropertyRevert::can_property_revert(skeleton, bone_scale_property, ¤t_scale); + if (can_revert_scale) { + bool is_valid = false; + Variant new_scale = EditorPropertyRevert::get_property_revert_value(skeleton, bone_scale_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_scale_property, current_scale); + ur->add_do_method(skeleton, "set", bone_scale_property, new_scale); + } + } + bool can_revert_rest = EditorPropertyRevert::can_property_revert(skeleton, bone_rest_property, ¤t_rest); + if (can_revert_rest) { + bool is_valid = false; + Variant new_rest = EditorPropertyRevert::get_property_revert_value(skeleton, bone_rest_property, &is_valid); + if (is_valid) { + ur->add_undo_method(skeleton, "set", bone_rest_property, current_rest); + ur->add_do_method(skeleton, "set", bone_rest_property, new_rest); + } + } + + ur->add_undo_method(this, "update_all"); + ur->add_do_method(this, "update_all"); + + ur->commit_action(); + } + return; +} + void Skeleton3DEditor::_update_properties() { if (pose_editor) { pose_editor->_update_properties(); @@ -693,15 +823,52 @@ void Skeleton3DEditor::update_joint_tree() { joint_item->set_selectable(0, true); joint_item->set_metadata(0, "bones/" + itos(current_bone_idx)); + String bone_enabled_property = "bones/" + itos(current_bone_idx) + "/enabled"; + String bone_parent_property = "bones/" + itos(current_bone_idx) + "/parent"; + String bone_name_property = "bones/" + itos(current_bone_idx) + "/name"; + String bone_position_property = "bones/" + itos(current_bone_idx) + "/position"; + String bone_rotation_property = "bones/" + itos(current_bone_idx) + "/rotation"; + String bone_scale_property = "bones/" + itos(current_bone_idx) + "/scale"; + String bone_rest_property = "bones/" + itos(current_bone_idx) + "/rest"; + + Variant current_enabled = skeleton->get(bone_enabled_property); + Variant current_parent = skeleton->get(bone_parent_property); + Variant current_name = skeleton->get(bone_name_property); + Variant current_position = skeleton->get(bone_position_property); + Variant current_rotation = skeleton->get(bone_rotation_property); + Variant current_scale = skeleton->get(bone_scale_property); + Variant current_rest = skeleton->get(bone_rest_property); + + bool can_revert_enabled = EditorPropertyRevert::can_property_revert(skeleton, bone_enabled_property, ¤t_enabled); + bool can_revert_parent = EditorPropertyRevert::can_property_revert(skeleton, bone_parent_property, ¤t_parent); + bool can_revert_name = EditorPropertyRevert::can_property_revert(skeleton, bone_name_property, ¤t_name); + bool can_revert_position = EditorPropertyRevert::can_property_revert(skeleton, bone_position_property, ¤t_position); + bool can_revert_rotation = EditorPropertyRevert::can_property_revert(skeleton, bone_rotation_property, ¤t_rotation); + bool can_revert_scale = EditorPropertyRevert::can_property_revert(skeleton, bone_scale_property, ¤t_scale); + bool can_revert_rest = EditorPropertyRevert::can_property_revert(skeleton, bone_rest_property, ¤t_rest); + + if (can_revert_enabled || can_revert_parent || can_revert_name || can_revert_position || can_revert_rotation || can_revert_scale || can_revert_rest) { + joint_item->add_button(0, get_editor_theme_icon(SNAME("ReloadSmall")), JOINT_BUTTON_REVERT, false, TTR("Revert")); + } + // Add the bone's children to the list of bones to be processed. Vector current_bone_child_bones = skeleton->get_bone_children(current_bone_idx); int child_bone_size = current_bone_child_bones.size(); for (int i = 0; i < child_bone_size; i++) { bones_to_process.push_back(current_bone_child_bones[i]); } + + if (current_bone_idx == selected_bone) { + joint_item->select(0); + } } } +void Skeleton3DEditor::update_all() { + _update_properties(); + update_joint_tree(); +} + void Skeleton3DEditor::create_editors() { set_h_size_flags(SIZE_EXPAND_FILL); set_focus_mode(FOCUS_ALL); @@ -840,6 +1007,7 @@ void Skeleton3DEditor::_notification(int p_what) { joint_tree->connect(SceneStringName(item_selected), callable_mp(this, &Skeleton3DEditor::_joint_tree_selection_changed)); joint_tree->connect("item_mouse_selected", callable_mp(this, &Skeleton3DEditor::_joint_tree_rmb_select)); + joint_tree->connect("button_clicked", callable_mp(this, &Skeleton3DEditor::_joint_tree_button_clicked)); #ifdef TOOLS_ENABLED skeleton->connect(SceneStringName(pose_updated), callable_mp(this, &Skeleton3DEditor::_draw_gizmo)); skeleton->connect(SceneStringName(pose_updated), callable_mp(this, &Skeleton3DEditor::_update_properties)); @@ -1337,6 +1505,10 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c ur->add_undo_method(skeleton, "set_bone_pose_scale", p_ids[i], se->get_bone_original_scale()); } } + + ur->add_do_method(se, "update_joint_tree"); + ur->add_undo_method(se, "update_joint_tree"); + ur->commit_action(); } diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index 79dc16ae2f6..0bb58aac233 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -96,6 +96,8 @@ public: class Skeleton3DEditor : public VBoxContainer { GDCLASS(Skeleton3DEditor, VBoxContainer); + static void _bind_methods(); + friend class Skeleton3DEditorPlugin; enum SkeletonOption { @@ -116,6 +118,10 @@ class Skeleton3DEditor : public VBoxContainer { Skeleton3D *skeleton = nullptr; + enum { + JOINT_BUTTON_REVERT = 0, + }; + Tree *joint_tree = nullptr; BoneTransformEditor *rest_editor = nullptr; BoneTransformEditor *pose_editor = nullptr; @@ -149,6 +155,7 @@ class Skeleton3DEditor : public VBoxContainer { EditorFileDialog *file_export_lib = nullptr; void update_joint_tree(); + void update_all(); void create_editors(); @@ -189,6 +196,7 @@ class Skeleton3DEditor : public VBoxContainer { void _joint_tree_selection_changed(); void _joint_tree_rmb_select(const Vector2 &p_pos, MouseButton p_button); + void _joint_tree_button_clicked(Object *p_item, int p_column, int p_id, MouseButton p_button); void _update_properties(); void _subgizmo_selection_change();