Browse Source

Merge pull request #51459 from TokageItLab/fix-animation-track-editor-insert-queue

Fixed behavior of insert track queue in `AnimationTrackEditor` is unstable
Rémi Verschelde 3 năm trước cách đây
mục cha
commit
90fd6e960e

+ 149 - 167
editor/animation_track_editor.cpp

@@ -541,7 +541,7 @@ public:
 					String hint_string;
 
 					if (v.get_type() == Variant::OBJECT) {
-						//could actually check the object property if exists..? yes i will!
+						// Could actually check the object property if exists..? Yes I will!
 						Ref<Resource> res = v;
 						if (res.is_valid()) {
 							hint = PROPERTY_HINT_RESOURCE_TYPE;
@@ -1177,7 +1177,7 @@ public:
 							String hint_string;
 
 							if (v.get_type() == Variant::OBJECT) {
-								//could actually check the object property if exists..? yes i will!
+								// Could actually check the object property if exists..? Yes I will!
 								Ref<Resource> res = v;
 								if (res.is_valid()) {
 									hint = PROPERTY_HINT_RESOURCE_TYPE;
@@ -1388,7 +1388,7 @@ void AnimationTimelineEdit::_notification(int p_what) {
 
 		float l = animation->get_length();
 		if (l <= 0) {
-			l = 0.001; //avoid crashor
+			l = 0.001; // Avoid crashor.
 		}
 
 		Ref<Texture2D> hsize_icon = get_theme_icon(SNAME("Hsize"), SNAME("EditorIcons"));
@@ -1401,18 +1401,12 @@ void AnimationTimelineEdit::_notification(int p_what) {
 			for (int i = 0; i < animation->get_track_count(); i++) {
 				if (animation->track_get_key_count(i) > 0) {
 					float beg = animation->track_get_key_time(i, 0);
-					/*if (animation->track_get_type(i) == Animation::TYPE_BEZIER) {
-						beg += animation->bezier_track_get_key_in_handle(i, 0).x;
-					}* not worth it since they have no use */
 
 					if (beg < time_min) {
 						time_min = beg;
 					}
 
 					float end = animation->track_get_key_time(i, animation->track_get_key_count(i) - 1);
-					/*if (animation->track_get_type(i) == Animation::TYPE_BEZIER) {
-						end += animation->bezier_track_get_key_out_handle(i, animation->track_get_key_count(i) - 1).x;
-					} not worth it since they have no use */
 
 					if (end > time_max) {
 						time_max = end;
@@ -1422,8 +1416,6 @@ void AnimationTimelineEdit::_notification(int p_what) {
 
 			float extra = (zoomw / scale) * 0.5;
 
-			//if (time_min < -0.001)
-			//	time_min -= extra;
 			time_max += extra;
 			set_min(time_min);
 			set_max(time_max);
@@ -1853,7 +1845,7 @@ void AnimationTrackEdit::_notification(int p_what) {
 		{
 			Ref<Texture2D> check = animation->track_is_enabled(track) ? get_theme_icon(SNAME("checked"), SNAME("CheckBox")) : get_theme_icon(SNAME("unchecked"), SNAME("CheckBox"));
 
-			int ofs = in_group ? check->get_width() : 0; //not the best reference for margin but..
+			int ofs = in_group ? check->get_width() : 0; // Not the best reference for margin but..
 
 			check_rect = Rect2(Point2(ofs, int(get_size().height - check->get_height()) / 2), check->get_size());
 			draw_texture(check, check_rect.position);
@@ -1971,7 +1963,7 @@ void AnimationTrackEdit::_notification(int p_what) {
 
 			ofs += hsep;
 			{
-				//callmode
+				// Callmode.
 
 				Animation::UpdateMode update_mode;
 
@@ -1990,7 +1982,7 @@ void AnimationTrackEdit::_notification(int p_what) {
 				if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
 					draw_texture(update_icon, update_mode_rect.position);
 				}
-				//make it easier to click
+				// Make it easier to click.
 				update_mode_rect.position.y = 0;
 				update_mode_rect.size.y = get_size().height;
 
@@ -2019,7 +2011,7 @@ void AnimationTrackEdit::_notification(int p_what) {
 			}
 
 			{
-				//interp
+				// Interp.
 
 				Animation::InterpolationType interp_mode = animation->track_get_interpolation_type(track);
 
@@ -2032,7 +2024,7 @@ void AnimationTrackEdit::_notification(int p_what) {
 				if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM3D) {
 					draw_texture(icon, interp_mode_rect.position);
 				}
-				//make it easier to click
+				// Make it easier to click.
 				interp_mode_rect.position.y = 0;
 				interp_mode_rect.size.y = get_size().height;
 
@@ -2052,7 +2044,7 @@ void AnimationTrackEdit::_notification(int p_what) {
 			}
 
 			{
-				//loop
+				// Loop.
 
 				bool loop_wrap = animation->track_get_interpolation_loop_wrap(track);
 
@@ -2085,7 +2077,7 @@ void AnimationTrackEdit::_notification(int p_what) {
 			}
 
 			{
-				//erase
+				// Erase.
 
 				Ref<Texture2D> icon = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"));
 
@@ -2132,7 +2124,7 @@ Rect2 AnimationTrackEdit::get_key_rect(int p_index, float p_pixels_sec) {
 	}
 	Rect2 rect = Rect2(-type_icon->get_width() / 2, 0, type_icon->get_width(), get_size().height);
 
-	//make it a big easier to click
+	// Make it a big easier to click.
 	rect.position.x -= rect.size.x * 0.5;
 	rect.size.x *= 2;
 	return rect;
@@ -2221,7 +2213,7 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool
 	draw_texture(icon_to_draw, ofs);
 }
 
-//helper
+// Helper.
 void AnimationTrackEdit::draw_rect_clipped(const Rect2 &p_rect, const Color &p_color, bool p_filled) {
 	int clip_left = timeline->get_name_limit();
 	int clip_right = get_size().width - timeline->get_buttons_width();
@@ -2246,7 +2238,7 @@ void AnimationTrackEdit::draw_texture_region_clipped(const Ref<Texture2D> &p_tex
 	int clip_left = timeline->get_name_limit();
 	int clip_right = get_size().width - timeline->get_buttons_width();
 
-	//clip left and right
+	// Clip left and right.
 	if (clip_left > p_rect.position.x + p_rect.size.x) {
 		return;
 	}
@@ -2455,7 +2447,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
 						key_distance = distance;
 					}
 				} else {
-					//first one does it
+					// First one does it.
 					break;
 				}
 			}
@@ -3001,7 +2993,7 @@ AnimationTrackEdit::AnimationTrackEdit() {
 	play_position->set_anchors_and_offsets_preset(PRESET_WIDE);
 	play_position->connect("draw", callable_mp(this, &AnimationTrackEdit::_play_position_draw));
 	set_focus_mode(FOCUS_CLICK);
-	set_mouse_filter(MOUSE_FILTER_PASS); //scroll has to work too for selection
+	set_mouse_filter(MOUSE_FILTER_PASS); // Scroll has to work too for selection.
 }
 
 //////////////////////////////////////
@@ -3338,30 +3330,16 @@ static bool track_type_is_resettable(Animation::TrackType p_type) {
 	}
 }
 
-void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
-	if (insert_frame != Engine::get_singleton()->get_frames_drawn()) {
-		//clear insert list for the frame if frame changed
-		if (insert_confirm->is_visible()) {
-			return; //do nothing
-		}
-		insert_data.clear();
-		insert_query = false;
-	}
-	insert_frame = Engine::get_singleton()->get_frames_drawn();
-
-	for (const InsertData &E : insert_data) {
-		//prevent insertion of multiple tracks
-		if (E.path == p_id.path) {
-			return; //already inserted a track for this on this frame
-		}
-	}
-
-	insert_data.push_back(p_id);
+void AnimationTrackEditor::make_insert_queue() {
+	insert_data.clear();
+	insert_queue = true;
+}
 
+void AnimationTrackEditor::commit_insert_queue() {
 	bool reset_allowed = true;
 	AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player();
 	if (player->has_animation("RESET") && player->get_animation("RESET") == animation) {
-		// Avoid messing with the reset animation itself
+		// Avoid messing with the reset animation itself.
 		reset_allowed = false;
 	} else {
 		bool some_resettable = false;
@@ -3376,74 +3354,82 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
 		}
 	}
 
-	if (p_id.track_idx == -1) {
-		int num_tracks = 0;
-		bool all_bezier = true;
-		for (int i = 0; i < insert_data.size(); i++) {
-			if (insert_data[i].type != Animation::TYPE_VALUE && insert_data[i].type != Animation::TYPE_BEZIER) {
-				all_bezier = false;
-			}
-
-			if (insert_data[i].track_idx == -1) {
-				++num_tracks;
-			}
+	// Organize insert data.
+	int num_tracks = 0;
+	String last_track_query;
+	bool all_bezier = true;
+	for (int i = 0; i < insert_data.size(); i++) {
+		if (insert_data[i].type != Animation::TYPE_VALUE && insert_data[i].type != Animation::TYPE_BEZIER) {
+			all_bezier = false;
+		}
 
-			if (insert_data[i].type != Animation::TYPE_VALUE) {
-				continue;
-			}
+		if (insert_data[i].track_idx == -1) {
+			++num_tracks;
+			last_track_query = insert_data[i].query;
+		}
 
-			switch (insert_data[i].value.get_type()) {
-				case Variant::INT:
-				case Variant::FLOAT:
-				case Variant::VECTOR2:
-				case Variant::VECTOR3:
-				case Variant::QUATERNION:
-				case Variant::PLANE:
-				case Variant::COLOR: {
-					// Valid.
-				} break;
-				default: {
-					all_bezier = false;
-				}
-			}
+		if (insert_data[i].type != Animation::TYPE_VALUE) {
+			continue;
 		}
 
-		if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) {
-			//potential new key, does not exist
-			if (num_tracks == 1) {
-				// TRANSLATORS: %s will be replaced by a phrase describing the target of track.
-				insert_confirm_text->set_text(vformat(TTR("Create new track for %s and insert key?"), p_id.query));
-			} else {
-				insert_confirm_text->set_text(vformat(TTR("Create %d new tracks and insert keys?"), num_tracks));
+		switch (insert_data[i].value.get_type()) {
+			case Variant::INT:
+			case Variant::FLOAT:
+			case Variant::VECTOR2:
+			case Variant::VECTOR3:
+			case Variant::QUATERNION:
+			case Variant::PLANE:
+			case Variant::COLOR: {
+				// Valid.
+			} break;
+			default: {
+				all_bezier = false;
 			}
+		}
+	}
 
-			insert_confirm_bezier->set_visible(all_bezier);
-			insert_confirm_reset->set_visible(reset_allowed);
-
-			insert_confirm->get_ok_button()->set_text(TTR("Create"));
-			insert_confirm->popup_centered();
-			insert_query = true;
+	if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true)) && num_tracks > 0) {
+		// Potentially a new key, does not exist.
+		if (num_tracks == 1) {
+			// TRANSLATORS: %s will be replaced by a phrase describing the target of track.
+			insert_confirm_text->set_text(vformat(TTR("Create new track for %s and insert key?"), last_track_query));
 		} else {
-			call_deferred(SNAME("_insert_delay"), reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), all_bezier && EDITOR_GET("editors/animation/default_create_bezier_tracks"));
-			insert_queue = true;
+			insert_confirm_text->set_text(vformat(TTR("Create %d new tracks and insert keys?"), num_tracks));
 		}
 
+		insert_confirm_bezier->set_visible(all_bezier);
+		insert_confirm_reset->set_visible(reset_allowed);
+
+		insert_confirm->get_ok_button()->set_text(TTR("Create"));
+		insert_confirm->popup_centered();
 	} else {
-		if (!insert_query && !insert_queue) {
-			// Create Beziers wouldn't make sense in this case, where no tracks are being created
-			call_deferred(SNAME("_insert_delay"), reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), false);
-			insert_queue = true;
-		}
+		_insert_track(reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), all_bezier && EDITOR_GET("editors/animation/default_create_bezier_tracks"));
 	}
+
+	insert_queue = false;
 }
 
-void AnimationTrackEditor::_insert_delay(bool p_create_reset, bool p_create_beziers) {
-	if (insert_query) {
-		//discard since it's entered into query mode
-		insert_queue = false;
-		return;
+void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
+	if (!insert_queue) {
+		insert_data.clear();
+	}
+
+	for (const InsertData &E : insert_data) {
+		// Prevent insertion of multiple tracks.
+		if (E.path == p_id.path) {
+			return; // Already inserted a track this frame.
+		}
 	}
 
+	insert_data.push_back(p_id);
+
+	// Without queue, commit immediately.
+	if (!insert_queue) {
+		commit_insert_queue();
+	}
+}
+
+void AnimationTrackEditor::_insert_track(bool p_create_reset, bool p_create_beziers) {
 	undo_redo->create_action(TTR("Anim Insert"));
 
 	Ref<Animation> reset_anim;
@@ -3478,7 +3464,6 @@ void AnimationTrackEditor::_insert_delay(bool p_create_reset, bool p_create_bezi
 		set_anim_pos(pos);
 		emit_signal(SNAME("timeline_changed"), pos, true);
 	}
-	insert_queue = false;
 }
 
 void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Transform3D &p_xform) {
@@ -3490,7 +3475,7 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_
 	}
 
 	ERR_FAIL_COND(!root);
-	//let's build a node path
+	// Let's build a node path.
 	String path = root->get_path_to(p_node);
 	if (p_sub != "") {
 		path += ":" + p_sub;
@@ -3523,8 +3508,7 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_
 	id.query = vformat(TTR("node '%s'"), p_node->get_name());
 	id.advance = false;
 
-	//dialog insert
-
+	// Dialog insert.
 	_query_insert(id);
 }
 
@@ -3556,12 +3540,12 @@ bool AnimationTrackEditor::has_transform_track(Node3D *p_node, const String &p_s
 void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant &p_value) {
 	String path = p_path;
 
-	//animation property is a special case, always creates an animation track
+	// Animation property is a special case, always creates an animation track.
 	for (int i = 0; i < animation->get_track_count(); i++) {
 		String np = animation->track_get_path(i);
 
 		if (path == np && animation->track_get_type(i) == Animation::TYPE_ANIMATION) {
-			//exists
+			// Exists.
 			InsertData id;
 			id.path = path;
 			id.track_idx = i;
@@ -3570,7 +3554,7 @@ void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant
 			// TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
 			id.query = TTR("animation");
 			id.advance = false;
-			//dialog insert
+			// Dialog insert.
 			_query_insert(id);
 			return;
 		}
@@ -3583,13 +3567,13 @@ void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant
 	id.type = Animation::TYPE_ANIMATION;
 	id.query = TTR("animation");
 	id.advance = false;
-	//dialog insert
+	// Dialog insert.
 	_query_insert(id);
 }
 
 void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists) {
 	ERR_FAIL_COND(!root);
-	//let's build a node path
+	// Let's build a node path.
 
 	Node *node = p_node;
 
@@ -3615,7 +3599,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p
 
 	NodePath np = path;
 
-	//locate track
+	// Locate track.
 
 	bool inserted = false;
 
@@ -3633,14 +3617,14 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p
 			// TRANSLATORS: This describes the target of new animation track, will be inserted into another string.
 			id.query = vformat(TTR("property '%s'"), p_property);
 			id.advance = false;
-			//dialog insert
+			// Dialog insert.
 			_query_insert(id);
 			inserted = true;
 		} else if (animation->track_get_type(i) == Animation::TYPE_BEZIER) {
 			Variant value;
 			String track_path = animation->track_get_path(i);
 			if (track_path == np) {
-				value = p_value; //all good
+				value = p_value; // All good.
 			} else {
 				int sep = track_path.rfind(":");
 				if (sep != -1) {
@@ -3663,7 +3647,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p
 			id.type = Animation::TYPE_BEZIER;
 			id.query = vformat(TTR("property '%s'"), p_property);
 			id.advance = false;
-			//dialog insert
+			// Dialog insert.
 			_query_insert(id);
 			inserted = true;
 		}
@@ -3679,7 +3663,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p
 	id.type = Animation::TYPE_VALUE;
 	id.query = vformat(TTR("property '%s'"), p_property);
 	id.advance = false;
-	//dialog insert
+	// Dialog insert.
 	_query_insert(id);
 }
 
@@ -3687,7 +3671,7 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari
 	EditorHistory *history = EditorNode::get_singleton()->get_editor_history();
 
 	ERR_FAIL_COND(!root);
-	//let's build a node path
+	// Let's build a node path.
 	ERR_FAIL_COND(history->get_path_size() == 0);
 	Object *obj = ObjectDB::get_instance(history->get_path_object(0));
 	ERR_FAIL_COND(!Object::cast_to<Node>(obj));
@@ -3715,10 +3699,11 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari
 
 	NodePath np = path;
 
-	//locate track
+	// Locate track.
 
 	bool inserted = false;
 
+	make_insert_queue();
 	for (int i = 0; i < animation->get_track_count(); i++) {
 		if (animation->track_get_type(i) == Animation::TYPE_VALUE) {
 			if (animation->track_get_path(i) != np) {
@@ -3732,13 +3717,13 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari
 			id.type = Animation::TYPE_VALUE;
 			id.query = vformat(TTR("property '%s'"), p_property);
 			id.advance = p_advance;
-			//dialog insert
+			// Dialog insert.
 			_query_insert(id);
 			inserted = true;
 		} else if (animation->track_get_type(i) == Animation::TYPE_BEZIER) {
 			Variant value;
 			if (animation->track_get_path(i) == np) {
-				value = p_value; //all good
+				value = p_value; // All good.
 			} else {
 				String tpath = animation->track_get_path(i);
 				int index = tpath.rfind(":");
@@ -3757,11 +3742,12 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari
 			id.type = Animation::TYPE_BEZIER;
 			id.query = vformat(TTR("property '%s'"), p_property);
 			id.advance = p_advance;
-			//dialog insert
+			// Dialog insert.
 			_query_insert(id);
 			inserted = true;
 		}
 	}
+	commit_insert_queue();
 
 	if (!inserted) {
 		InsertData id;
@@ -3771,7 +3757,7 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari
 		id.type = Animation::TYPE_VALUE;
 		id.query = vformat(TTR("property '%s'"), p_property);
 		id.advance = p_advance;
-		//dialog insert
+		// Dialog insert.
 		_query_insert(id);
 	}
 }
@@ -3954,7 +3940,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
 				animation->add_track(p_id.type);
 				animation->track_set_path(animation->get_track_count() - 1, p_id.path);
 				PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
-				animation->remove_track(animation->get_track_count() - 1); //hack
+				animation->remove_track(animation->get_track_count() - 1); // Hack.
 
 				if (h.type == Variant::FLOAT ||
 						h.type == Variant::VECTOR2 ||
@@ -4103,7 +4089,7 @@ void AnimationTrackEditor::_update_tracks() {
 	for (int i = 0; i < animation->get_track_count(); i++) {
 		AnimationTrackEdit *track_edit = nullptr;
 
-		//find hint and info for plugin
+		// Find hint and info for plugin.
 
 		if (use_filter) {
 			NodePath path = animation->track_get_path(i);
@@ -4111,10 +4097,10 @@ void AnimationTrackEditor::_update_tracks() {
 			if (root && root->has_node(path)) {
 				Node *node = root->get_node(path);
 				if (!node) {
-					continue; // no node, no filter
+					continue; // No node, no filter.
 				}
 				if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
-					continue; //skip track due to not selected
+					continue; // Skip track due to not selected.
 				}
 			}
 		}
@@ -4176,7 +4162,7 @@ void AnimationTrackEditor::_update_tracks() {
 		}
 
 		if (track_edit == nullptr) {
-			//no valid plugin_found
+			// No valid plugin_found.
 			track_edit = memnew(AnimationTrackEdit);
 		}
 
@@ -4251,11 +4237,11 @@ void AnimationTrackEditor::_update_tracks() {
 
 void AnimationTrackEditor::_animation_changed() {
 	if (animation_changing_awaiting_update) {
-		return; //all will be updated, don't bother with anything
+		return; // All will be updated, don't bother with anything.
 	}
 
 	if (key_edit && key_edit->setting) {
-		//if editing a key, just update the edited track, makes refresh less costly
+		// If editing a key, just update the edited track, makes refresh less costly.
 		if (key_edit->track < track_edits.size()) {
 			if (animation->track_get_type(key_edit->track) == Animation::TYPE_BEZIER) {
 				bezier_edit->update();
@@ -4309,7 +4295,7 @@ void AnimationTrackEditor::_animation_update() {
 	}
 
 	if (track_edits.size() == animation->get_track_count()) {
-		//check tracks are the same
+		// Check tracks are the same.
 
 		for (int i = 0; i < track_edits.size(); i++) {
 			if (track_edits[i]->get_path() != animation->track_get_path(i)) {
@@ -4503,12 +4489,12 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) {
 	if (adding_track_type == Animation::TYPE_VALUE) {
 		Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE;
 		{
-			//hack
+			// Hack.
 			NodePath np;
 			animation->add_track(Animation::TYPE_VALUE);
 			animation->track_set_path(animation->get_track_count() - 1, full_path);
 			PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
-			animation->remove_track(animation->get_track_count() - 1); //hack
+			animation->remove_track(animation->get_track_count() - 1); // Hack.
 			if (h.type == Variant::FLOAT ||
 					h.type == Variant::VECTOR2 ||
 					h.type == Variant::RECT2 ||
@@ -4536,12 +4522,12 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) {
 	} else {
 		Vector<String> subindices;
 		{
-			//hack
+			// Hack.
 			NodePath np;
 			animation->add_track(Animation::TYPE_VALUE);
 			animation->track_set_path(animation->get_track_count() - 1, full_path);
 			PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
-			animation->remove_track(animation->get_track_count() - 1); //hack
+			animation->remove_track(animation->get_track_count() - 1); // Hack.
 			bool valid;
 			subindices = _get_bezier_subindices_for_type(h.type, &valid);
 			if (!valid) {
@@ -4593,7 +4579,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
 	if (snap->is_pressed() && step->get_value() != 0) {
 		p_ofs = snap_time(p_ofs);
 	}
-	while (animation->track_find_key(p_track, p_ofs, true) != -1) { //make sure insertion point is valid
+	while (animation->track_find_key(p_track, p_ofs, true) != -1) { // Make sure insertion point is valid.
 		p_ofs += 0.001;
 	}
 
@@ -4788,16 +4774,16 @@ struct _AnimMoveRestore {
 	Variant key;
 	float transition = 0;
 };
-//used for undo/redo
+// Used for undo/redo.
 
 void AnimationTrackEditor::_clear_key_edit() {
 	if (key_edit) {
-		//if key edit is the object being inspected, remove it first
+		// If key edit is the object being inspected, remove it first.
 		if (EditorNode::get_singleton()->get_inspector()->get_edited_object() == key_edit) {
 			EditorNode::get_singleton()->push_item(nullptr);
 		}
 
-		//then actually delete it
+		// Then actually delete it.
 		memdelete(key_edit);
 		key_edit = nullptr;
 	}
@@ -4911,11 +4897,11 @@ void AnimationTrackEditor::_move_selection_commit() {
 	List<_AnimMoveRestore> to_restore;
 
 	float motion = moving_selection_offset;
-	// 1 - remove the keys
+	// 1 - remove the keys.
 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 		undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key);
 	}
-	// 2 - remove overlapped keys
+	// 2 - Remove overlapped keys.
 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 		float newtime = snap_time(E->get().pos + motion);
 		int idx = animation->track_find_key(E->key().track, newtime, true);
@@ -4926,7 +4912,7 @@ void AnimationTrackEditor::_move_selection_commit() {
 		sk.key = idx;
 		sk.track = E->key().track;
 		if (selection.has(sk)) {
-			continue; //already in selection, don't save
+			continue; // Already in selection, don't save.
 		}
 
 		undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newtime);
@@ -4940,24 +4926,24 @@ void AnimationTrackEditor::_move_selection_commit() {
 		to_restore.push_back(amr);
 	}
 
-	// 3 - move the keys (re insert them)
+	// 3 - Move the keys (Reinsert them).
 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 		float newpos = snap_time(E->get().pos + motion);
 		undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
 	}
 
-	// 4 - (undo) remove inserted keys
+	// 4 - (Undo) Remove inserted keys.
 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 		float newpos = snap_time(E->get().pos + motion);
 		undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos);
 	}
 
-	// 5 - (undo) reinsert keys
+	// 5 - (Undo) Reinsert keys.
 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 		undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
 	}
 
-	// 6 - (undo) reinsert overlapped keys
+	// 6 - (Undo) Reinsert overlapped keys.
 	for (_AnimMoveRestore &amr : to_restore) {
 		undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, amr.transition);
 	}
@@ -4965,7 +4951,7 @@ void AnimationTrackEditor::_move_selection_commit() {
 	undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
 	undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
 
-	// 7 - reselect
+	// 7 - Reselect.
 	for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 		float oldpos = E->get().pos;
 		float newpos = snap_time(oldpos + motion);
@@ -5035,18 +5021,18 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
 			box_select_rect = Rect2();
 		} else if (box_selecting) {
 			if (box_selection->is_visible_in_tree()) {
-				//only if moved
+				// Only if moved.
 				for (int i = 0; i < track_edits.size(); i++) {
 					Rect2 local_rect = box_select_rect;
 					local_rect.position -= track_edits[i]->get_global_position();
 					track_edits[i]->append_to_selection(local_rect, mb->is_command_pressed());
 				}
 
-				if (_get_track_selected() == -1 && track_edits.size() > 0) { //minimal hack to make shortcuts work
+				if (_get_track_selected() == -1 && track_edits.size() > 0) { // Minimal hack to make shortcuts work.
 					track_edits[track_edits.size() - 1]->grab_focus();
 				}
 			} else {
-				_clear_selection(); //clear it
+				_clear_selection(); // Clear it.
 			}
 
 			box_selection->hide();
@@ -5062,7 +5048,7 @@ void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
 
 	if (mm.is_valid() && box_selecting) {
 		if (!(mm->get_button_mask() & MOUSE_BUTTON_MASK_LEFT)) {
-			//no longer
+			// No longer.
 			box_selection->hide();
 			box_selecting = false;
 			return;
@@ -5102,16 +5088,16 @@ void AnimationTrackEditor::_cancel_bezier_edit() {
 }
 
 void AnimationTrackEditor::_bezier_edit(int p_for_track) {
-	_clear_selection(); //bezier probably wants to use a separate selection mode
+	_clear_selection(); // Bezier probably wants to use a separate selection mode.
 	bezier_edit->set_root(root);
 	bezier_edit->set_animation_and_track(animation, p_for_track);
 	scroll->hide();
 	bezier_edit->show();
-	//search everything within the track and curve- edit it
+	// Search everything within the track and curve - edit it.
 }
 
 void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
-	//duplicait!
+	// Duplicait!
 	if (selection.size() && animation.is_valid() && (!transpose || (_get_track_selected() >= 0 && _get_track_selected() < animation->get_track_count()))) {
 		int top_track = 0x7FFFFFFF;
 		float top_time = 1e10;
@@ -5169,7 +5155,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
 
 		undo_redo->commit_action();
 
-		//reselect duplicated
+		// Reselect duplicated.
 
 		Map<SelectedKey, KeyInfo> new_selection;
 		for (const Pair<int, float> &E : new_selection_values) {
@@ -5281,7 +5267,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
 						text += sn[j];
 					}
 
-					path = NodePath(node->get_path().get_names(), path.get_subnames(), true); //store full path instead for copying
+					path = NodePath(node->get_path().get_names(), path.get_subnames(), true); // Store full path instead for copying.
 				} else {
 					text = path;
 					int sep = text.find(":");
@@ -5435,11 +5421,11 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
 
 			List<_AnimMoveRestore> to_restore;
 
-			// 1-remove the keys
+			// 1 - Remove the keys.
 			for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 				undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key);
 			}
-			// 2- remove overlapped keys
+			// 2 - Remove overlapped keys.
 			for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 				float newtime = (E->get().pos - from_t) * s + from_t;
 				int idx = animation->track_find_key(E->key().track, newtime, true);
@@ -5450,7 +5436,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
 				sk.key = idx;
 				sk.track = E->key().track;
 				if (selection.has(sk)) {
-					continue; //already in selection, don't save
+					continue; // Already in selection, don't save.
 				}
 
 				undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newtime);
@@ -5465,24 +5451,24 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
 			}
 
 #define _NEW_POS(m_ofs) (((s > 0) ? m_ofs : from_t + (len - (m_ofs - from_t))) - pivot) * ABS(s) + from_t
-			// 3-move the keys (re insert them)
+			// 3 - Move the keys (re insert them).
 			for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 				float newpos = _NEW_POS(E->get().pos);
 				undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
 			}
 
-			// 4-(undo) remove inserted keys
+			// 4 - (Undo) Remove inserted keys.
 			for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 				float newpos = _NEW_POS(E->get().pos);
 				undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos);
 			}
 
-			// 5-(undo) reinsert keys
+			// 5 - (Undo) Reinsert keys.
 			for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 				undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
 			}
 
-			// 6-(undo) reinsert overlapped keys
+			// 6 - (Undo) Reinsert overlapped keys.
 			for (_AnimMoveRestore &amr : to_restore) {
 				undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, amr.transition);
 			}
@@ -5490,7 +5476,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
 			undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
 			undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
 
-			// 7-reselect
+			// 7-reselect.
 			for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
 				float oldpos = E->get().pos;
 				float newpos = _NEW_POS(oldpos);
@@ -5639,7 +5625,7 @@ bool AnimationTrackEditor::is_grouping_tracks() {
 
 void AnimationTrackEditor::_selection_changed() {
 	if (selected_filter->is_pressed()) {
-		_update_tracks(); //needs updatin
+		_update_tracks(); // Needs updatin.
 	} else {
 		for (int i = 0; i < track_edits.size(); i++) {
 			track_edits[i]->update();
@@ -5708,7 +5694,6 @@ void AnimationTrackEditor::_bind_methods() {
 	ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update);
 	ClassDB::bind_method("_track_grab_focus", &AnimationTrackEditor::_track_grab_focus);
 	ClassDB::bind_method("_update_tracks", &AnimationTrackEditor::_update_tracks);
-	ClassDB::bind_method("_insert_delay", &AnimationTrackEditor::_insert_delay);
 	ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim);
 	ClassDB::bind_method("_select_at_anim", &AnimationTrackEditor::_select_at_anim);
 
@@ -5794,7 +5779,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
 	undo_redo = EditorNode::get_singleton()->get_undo_redo();
 
 	main_panel = memnew(PanelContainer);
-	main_panel->set_focus_mode(FOCUS_ALL); // allow panel to have focus so that shortcuts work as expected.
+	main_panel->set_focus_mode(FOCUS_ALL); // Allow panel to have focus so that shortcuts work as expected.
 	add_child(main_panel);
 	main_panel->set_v_size_flags(SIZE_EXPAND_FILL);
 	HBoxContainer *timeline_scroll = memnew(HBoxContainer);
@@ -5830,7 +5815,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
 	scroll->set_v_size_flags(SIZE_EXPAND_FILL);
 	VScrollBar *sb = scroll->get_v_scrollbar();
 	scroll->remove_child(sb);
-	timeline_scroll->add_child(sb); //move here so timeline and tracks are always aligned
+	timeline_scroll->add_child(sb); // Move here so timeline and tracks are always aligned.
 	scroll->connect("gui_input", callable_mp(this, &AnimationTrackEditor::_scroll_input));
 
 	bezier_edit = memnew(AnimationBezierTrackEdit);
@@ -5871,7 +5856,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
 
 	selected_filter = memnew(Button);
 	selected_filter->set_flat(true);
-	selected_filter->connect("pressed", callable_mp(this, &AnimationTrackEditor::_view_group_toggle)); //same function works the same
+	selected_filter->connect("pressed", callable_mp(this, &AnimationTrackEditor::_view_group_toggle)); // Same function works the same.
 	selected_filter->set_toggle_mode(true);
 	selected_filter->set_tooltip(TTR("Only show tracks from nodes selected in tree."));
 
@@ -5972,9 +5957,6 @@ AnimationTrackEditor::AnimationTrackEditor() {
 	add_child(method_selector);
 	method_selector->connect("selected", callable_mp(this, &AnimationTrackEditor::_add_method_key));
 
-	inserting = false;
-	insert_query = false;
-	insert_frame = 0;
 	insert_queue = false;
 
 	insert_confirm = memnew(ConfirmationDialog);
@@ -6007,13 +5989,13 @@ AnimationTrackEditor::AnimationTrackEditor() {
 	box_selection->connect("draw", callable_mp(this, &AnimationTrackEditor::_box_selection_draw));
 	box_selecting = false;
 
-	//default plugins
+	// Default Plugins.
 
 	Ref<AnimationTrackEditDefaultPlugin> def_plugin;
 	def_plugin.instantiate();
 	add_track_edit_plugin(def_plugin);
 
-	//dialogs
+	// Dialogs.
 
 	optimize_dialog = memnew(ConfirmationDialog);
 	add_child(optimize_dialog);

+ 3 - 4
editor/animation_track_editor.h

@@ -352,10 +352,7 @@ class AnimationTrackEditor : public VBoxContainer {
 	CheckBox *insert_confirm_reset;
 	ConfirmationDialog *insert_confirm;
 	bool insert_queue;
-	bool inserting;
-	bool insert_query;
 	List<InsertData> insert_data;
-	uint64_t insert_frame;
 
 	void _query_insert(const InsertData &p_id);
 	Ref<Animation> _create_and_get_reset_animation();
@@ -370,7 +367,7 @@ class AnimationTrackEditor : public VBoxContainer {
 		}
 	};
 	TrackIndices _confirm_insert(InsertData p_id, TrackIndices p_next_tracks, bool p_create_reset, Ref<Animation> p_reset_anim, bool p_create_beziers);
-	void _insert_delay(bool p_create_reset, bool p_create_beziers);
+	void _insert_track(bool p_create_reset, bool p_create_beziers);
 
 	void _root_removed(Node *p_root);
 
@@ -532,6 +529,8 @@ public:
 	void insert_value_key(const String &p_property, const Variant &p_value, bool p_advance);
 	void insert_transform_key(Node3D *p_node, const String &p_sub, const Transform3D &p_xform);
 	bool has_transform_track(Node3D *p_node, const String &p_sub);
+	void make_insert_queue();
+	void commit_insert_queue();
 
 	void show_select_node_warning(bool p_show);
 

+ 2 - 0
editor/plugins/skeleton_3d_editor_plugin.cpp

@@ -434,6 +434,7 @@ void Skeleton3DEditor::insert_keys(bool p_all_bones) {
 	String path = 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);
 
@@ -448,6 +449,7 @@ void Skeleton3DEditor::insert_keys(bool p_all_bones) {
 		Transform3D tform = skeleton->get_bone_pose(i);
 		te->insert_transform_key(skeleton, name, tform);
 	}
+	te->commit_insert_queue();
 }
 
 void Skeleton3DEditor::pose_to_rest() {