diff --git a/editor/icons/InsertKey.svg b/editor/icons/InsertKey.svg
new file mode 100644
index 00000000000..ace715a6248
--- /dev/null
+++ b/editor/icons/InsertKey.svg
@@ -0,0 +1 @@
+
diff --git a/editor/icons/InsertModKey.svg b/editor/icons/InsertModKey.svg
new file mode 100644
index 00000000000..a10d4b4cbd3
--- /dev/null
+++ b/editor/icons/InsertModKey.svg
@@ -0,0 +1 @@
+
diff --git a/editor/icons/NewKey.svg b/editor/icons/NewKey.svg
index 1eb5630c19c..287f76a119d 100644
--- a/editor/icons/NewKey.svg
+++ b/editor/icons/NewKey.svg
@@ -1 +1 @@
-
+
diff --git a/editor/icons/NewModKey.svg b/editor/icons/NewModKey.svg
new file mode 100644
index 00000000000..9e5fa5897ba
--- /dev/null
+++ b/editor/icons/NewModKey.svg
@@ -0,0 +1 @@
+
diff --git a/editor/icons/SkeletonModifier.svg b/editor/icons/SkeletonModifier.svg
new file mode 100644
index 00000000000..507b9df44ce
--- /dev/null
+++ b/editor/icons/SkeletonModifier.svg
@@ -0,0 +1 @@
+
diff --git a/editor/scene/3d/skeleton_3d_editor_plugin.cpp b/editor/scene/3d/skeleton_3d_editor_plugin.cpp
index df8997c4690..84b0e19507e 100644
--- a/editor/scene/3d/skeleton_3d_editor_plugin.cpp
+++ b/editor/scene/3d/skeleton_3d_editor_plugin.cpp
@@ -366,9 +366,7 @@ void Skeleton3DEditor::_bind_methods() {
}
void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) {
- if (!skeleton) {
- return;
- }
+ ERR_FAIL_COND(!skeleton);
switch (p_skeleton_option) {
case SKELETON_OPTION_RESET_ALL_POSES: {
@@ -399,9 +397,8 @@ void Skeleton3DEditor::_on_click_skeleton_option(int p_skeleton_option) {
}
void Skeleton3DEditor::reset_pose(const bool p_all_bones) {
- if (!skeleton) {
- return;
- }
+ ERR_FAIL_COND(!skeleton);
+
const int bone_count = skeleton->get_bone_count();
if (!bone_count) {
return;
@@ -434,16 +431,34 @@ void Skeleton3DEditor::reset_pose(const bool p_all_bones) {
ur->commit_action();
}
-void Skeleton3DEditor::insert_keys(const bool p_all_bones) {
+void Skeleton3DEditor::insert_keys(const bool p_all_bones, const bool p_enable_modifier) {
+ ERR_FAIL_COND(!skeleton);
+
AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor();
bool is_read_only = te->is_read_only();
if (is_read_only) {
te->popup_read_only_dialog();
return;
}
- if (!skeleton) {
- return;
+ if (p_enable_modifier) {
+ if (!skeleton->is_connected(SceneStringName(skeleton_updated), callable_mp(this, &Skeleton3DEditor::_insert_keys).bind(p_all_bones))) {
+ skeleton->connect(SceneStringName(skeleton_updated), callable_mp(this, &Skeleton3DEditor::_insert_keys).bind(p_all_bones), CONNECT_ONE_SHOT);
+ } else {
+ WARN_PRINT_ED("A skeleton_updated signal is already connected with _insert_keys().");
+ }
+ skeleton->force_update_deferred();
+ skeleton->notification(Skeleton3D::NOTIFICATION_UPDATE_SKELETON);
+ // Force disconnecting signal if remain the connecting just in case.
+ if (skeleton->is_connected(SceneStringName(skeleton_updated), callable_mp(this, &Skeleton3DEditor::_insert_keys).bind(p_all_bones))) {
+ skeleton->disconnect(SceneStringName(skeleton_updated), callable_mp(this, &Skeleton3DEditor::_insert_keys).bind(p_all_bones));
+ }
+ } else {
+ _insert_keys(p_all_bones);
}
+}
+
+void Skeleton3DEditor::_insert_keys(const bool p_all_bones) {
+ ERR_FAIL_COND(!skeleton);
bool pos_enabled = key_loc_button->is_pressed();
bool rot_enabled = key_rot_button->is_pressed();
@@ -453,6 +468,7 @@ void Skeleton3DEditor::insert_keys(const bool p_all_bones) {
Node *root = EditorNode::get_singleton()->get_tree()->get_root();
String path = String(root->get_path_to(skeleton));
+ AnimationTrackEditor *te = AnimationPlayerEditor::get_singleton()->get_track_editor();
te->make_insert_queue();
for (int i = 0; i < bone_len; i++) {
const String name = skeleton->get_bone_name(i);
@@ -475,9 +491,8 @@ void Skeleton3DEditor::insert_keys(const bool p_all_bones) {
}
void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
- if (!skeleton) {
- return;
- }
+ ERR_FAIL_COND(!skeleton);
+
const int bone_count = skeleton->get_bone_count();
if (!bone_count) {
return;
@@ -1053,42 +1068,67 @@ void Skeleton3DEditor::create_editors() {
key_loc_button = memnew(Button);
key_loc_button->set_theme_type_variation(SceneStringName(FlatButton));
key_loc_button->set_toggle_mode(true);
- key_loc_button->set_pressed(false);
+ key_loc_button->set_pressed(editor_plugin->loc_pressed);
key_loc_button->set_focus_mode(FOCUS_ACCESSIBILITY);
key_loc_button->set_tooltip_text(TTR("Translation mask for inserting keys."));
animation_hb->add_child(key_loc_button);
+ if (!key_loc_button->is_connected(SceneStringName(toggled), callable_mp(this, &Skeleton3DEditor::_loc_toggled))) {
+ key_loc_button->connect(SceneStringName(toggled), callable_mp(this, &Skeleton3DEditor::_loc_toggled));
+ }
key_rot_button = memnew(Button);
key_rot_button->set_theme_type_variation(SceneStringName(FlatButton));
key_rot_button->set_toggle_mode(true);
- key_rot_button->set_pressed(true);
+ key_rot_button->set_pressed(editor_plugin->rot_pressed);
key_rot_button->set_focus_mode(FOCUS_ACCESSIBILITY);
key_rot_button->set_tooltip_text(TTR("Rotation mask for inserting keys."));
animation_hb->add_child(key_rot_button);
+ if (!key_rot_button->is_connected(SceneStringName(toggled), callable_mp(this, &Skeleton3DEditor::_rot_toggled))) {
+ key_rot_button->connect(SceneStringName(toggled), callable_mp(this, &Skeleton3DEditor::_rot_toggled));
+ }
key_scale_button = memnew(Button);
key_scale_button->set_theme_type_variation(SceneStringName(FlatButton));
key_scale_button->set_toggle_mode(true);
- key_scale_button->set_pressed(false);
+ key_scale_button->set_pressed(editor_plugin->scl_pressed);
key_scale_button->set_focus_mode(FOCUS_ACCESSIBILITY);
key_scale_button->set_tooltip_text(TTR("Scale mask for inserting keys."));
animation_hb->add_child(key_scale_button);
+ if (!key_scale_button->is_connected(SceneStringName(toggled), callable_mp(this, &Skeleton3DEditor::_scl_toggled))) {
+ key_scale_button->connect(SceneStringName(toggled), callable_mp(this, &Skeleton3DEditor::_scl_toggled));
+ }
key_insert_button = memnew(Button);
key_insert_button->set_theme_type_variation(SceneStringName(FlatButton));
key_insert_button->set_focus_mode(FOCUS_ACCESSIBILITY);
- key_insert_button->connect(SceneStringName(pressed), callable_mp(this, &Skeleton3DEditor::insert_keys).bind(false));
+ key_insert_button->connect(SceneStringName(pressed), callable_mp(this, &Skeleton3DEditor::insert_keys).bind(false, false));
key_insert_button->set_tooltip_text(TTRC("Insert key (based on mask) for bones with an existing track."));
key_insert_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_to_existing_tracks", TTRC("Insert Key (Existing Tracks)"), Key::INSERT));
animation_hb->add_child(key_insert_button);
- key_insert_all_button = memnew(Button);
- key_insert_all_button->set_theme_type_variation(SceneStringName(FlatButton));
- key_insert_all_button->set_focus_mode(FOCUS_ACCESSIBILITY);
- key_insert_all_button->connect(SceneStringName(pressed), callable_mp(this, &Skeleton3DEditor::insert_keys).bind(true));
- key_insert_all_button->set_tooltip_text(TTRC("Insert key (based on mask) for all bones."));
- key_insert_all_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_of_all_bones", TTRC("Insert Key (All Bones)"), KeyModifierMask::CMD_OR_CTRL + Key::INSERT));
- animation_hb->add_child(key_insert_all_button);
+ key_insert_new_button = memnew(Button);
+ key_insert_new_button->set_theme_type_variation(SceneStringName(FlatButton));
+ key_insert_new_button->set_focus_mode(FOCUS_ACCESSIBILITY);
+ key_insert_new_button->connect(SceneStringName(pressed), callable_mp(this, &Skeleton3DEditor::insert_keys).bind(true, false));
+ key_insert_new_button->set_tooltip_text(TTRC("Insert key (based on mask) for all bones."));
+ key_insert_new_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_of_all_bones", TTRC("Insert Key (All Bones)"), KeyModifierMask::CMD_OR_CTRL + Key::INSERT));
+ animation_hb->add_child(key_insert_new_button);
+
+ key_mod_insert_button = memnew(Button);
+ key_mod_insert_button->set_theme_type_variation(SceneStringName(FlatButton));
+ key_mod_insert_button->set_focus_mode(FOCUS_ACCESSIBILITY);
+ key_mod_insert_button->connect(SceneStringName(pressed), callable_mp(this, &Skeleton3DEditor::insert_keys).bind(false, true));
+ key_mod_insert_button->set_tooltip_text(TTRC("Insert key (based on mask) for modified bones with an existing track."));
+ key_mod_insert_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_to_existing_tracks", TTRC("Insert Key (Existing Tracks)"), Key::INSERT));
+ animation_hb->add_child(key_mod_insert_button);
+
+ key_mod_insert_new_button = memnew(Button);
+ key_mod_insert_new_button->set_theme_type_variation(SceneStringName(FlatButton));
+ key_mod_insert_new_button->set_focus_mode(FOCUS_ACCESSIBILITY);
+ key_mod_insert_new_button->connect(SceneStringName(pressed), callable_mp(this, &Skeleton3DEditor::insert_keys).bind(true, true));
+ key_mod_insert_new_button->set_tooltip_text(TTRC("Insert new key (based on mask) for all modified bones."));
+ key_mod_insert_new_button->set_shortcut(ED_SHORTCUT("skeleton_3d_editor/insert_key_of_all_bones", TTRC("Insert Key (All Bones)"), KeyModifierMask::CMD_OR_CTRL + Key::INSERT));
+ animation_hb->add_child(key_mod_insert_new_button);
// Bone tree.
bones_section = memnew(EditorInspectorSection);
@@ -1122,6 +1162,25 @@ void Skeleton3DEditor::create_editors() {
set_keyable(te->has_keying());
}
+void Skeleton3DEditor::_loc_toggled(bool p_toggled_on) {
+ if (!editor_plugin) {
+ return;
+ }
+ editor_plugin->loc_pressed = p_toggled_on;
+}
+void Skeleton3DEditor::_rot_toggled(bool p_toggled_on) {
+ if (!editor_plugin) {
+ return;
+ }
+ editor_plugin->rot_pressed = p_toggled_on;
+}
+void Skeleton3DEditor::_scl_toggled(bool p_toggled_on) {
+ if (!editor_plugin) {
+ return;
+ }
+ editor_plugin->scl_pressed = p_toggled_on;
+}
+
void Skeleton3DEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -1148,8 +1207,10 @@ void Skeleton3DEditor::_notification(int p_what) {
key_loc_button->set_button_icon(get_editor_theme_icon(SNAME("KeyPosition")));
key_rot_button->set_button_icon(get_editor_theme_icon(SNAME("KeyRotation")));
key_scale_button->set_button_icon(get_editor_theme_icon(SNAME("KeyScale")));
- key_insert_button->set_button_icon(get_editor_theme_icon(SNAME("Key")));
- key_insert_all_button->set_button_icon(get_editor_theme_icon(SNAME("NewKey")));
+ key_insert_button->set_button_icon(get_editor_theme_icon(SNAME("InsertKey")));
+ key_insert_new_button->set_button_icon(get_editor_theme_icon(SNAME("NewKey")));
+ key_mod_insert_button->set_button_icon(get_editor_theme_icon(SNAME("InsertModKey")));
+ key_mod_insert_new_button->set_button_icon(get_editor_theme_icon(SNAME("NewModKey")));
bones_section->set_bg_color(get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor)));
update_joint_tree();
diff --git a/editor/scene/3d/skeleton_3d_editor_plugin.h b/editor/scene/3d/skeleton_3d_editor_plugin.h
index b898b5d9488..c2ce402bedd 100644
--- a/editor/scene/3d/skeleton_3d_editor_plugin.h
+++ b/editor/scene/3d/skeleton_3d_editor_plugin.h
@@ -147,7 +147,14 @@ class Skeleton3DEditor : public VBoxContainer {
Button *key_rot_button = nullptr;
Button *key_scale_button = nullptr;
Button *key_insert_button = nullptr;
- Button *key_insert_all_button = nullptr;
+ Button *key_insert_new_button = nullptr;
+ Button *key_mod_insert_button = nullptr;
+ Button *key_mod_insert_new_button = nullptr;
+
+ // To maintain the status while running editor.
+ void _loc_toggled(bool p_toggled_on);
+ void _rot_toggled(bool p_toggled_on);
+ void _scl_toggled(bool p_toggled_on);
EditorInspectorSection *bones_section = nullptr;
@@ -172,7 +179,8 @@ class Skeleton3DEditor : public VBoxContainer {
void reset_pose(const bool p_all_bones);
void pose_to_rest(const bool p_all_bones);
- void insert_keys(const bool p_all_bones);
+ void _insert_keys(const bool p_all_bones);
+ void insert_keys(const bool p_all_bones, const bool p_enable_modifier);
void create_physical_skeleton();
PhysicalBone3D *create_physical_bone(int bone_id, int bone_child_id, const Vector &bones_infos);
@@ -247,6 +255,10 @@ class EditorInspectorPluginSkeleton : public EditorInspectorPlugin {
Skeleton3DEditor *skel_editor = nullptr;
public:
+ bool loc_pressed = false;
+ bool rot_pressed = true;
+ bool scl_pressed = false;
+
virtual bool can_handle(Object *p_object) override;
virtual void parse_begin(Object *p_object) override;
};