Repository: godotengine/godot
File: editor/scene/sprite_frames_editor_plugin.cpp (C++)

Code before:
	clipboard_anim->animation_name = edited_anim;
	clipboard_anim->animation_speed = frames->get_animation_speed(edited_anim);
	clipboard_anim->animation_loop = frames->get_animation_loop(edited_anim);

	int frame_count = frames->get_frame_count(edited_anim);
	for (int i = 0; i < frame_count; ++i) {
		ClipboardSpriteFrames::Frame frame;
		frame.texture = frames->get_frame_texture(edited_anim, i);
		frame.duration = frames->get_frame_duration(edited_anim, i);
		clipboard_anim->frames.push_back(frame);
	}
	EditorSettings::get_singleton()->set_resource_clipboard(clipboard_anim);

	// Remove animation with undo/redo (no confirmation dialog).
	StringName new_edited;
	List<StringName> anim_names;
	frames->get_animation_list(&anim_names);
	anim_names.sort_custom<StringName::AlphCompare>();
	if (anim_names.size() >= 2) {
		if (edited_anim == anim_names.get(0)) {
			new_edited = anim_names.get(1);
		} else {
			new_edited = anim_names.get(0);
		}
	} else {
		new_edited = StringName();
	}

	EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
	undo_redo->create_action(TTR("Cut Animation"), UndoRedo::MERGE_DISABLE, frames.ptr());
	_rename_node_animation(undo_redo, false, edited_anim, new_edited, "");
	undo_redo->add_do_method(frames.ptr(), "remove_animation", edited_anim);
	undo_redo->add_undo_method(frames.ptr(), "add_animation", edited_anim);
	_rename_node_animation(undo_redo, true, edited_anim, edited_anim, edited_anim);
	undo_redo->add_undo_method(frames.ptr(), "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim));
	undo_redo->add_undo_method(frames.ptr(), "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim));
	for (int i = 0; i < frame_count; i++) {
		Ref<Texture2D> texture = clipboard_anim->frames[i].texture;
		float duration = clipboard_anim->frames[i].duration;
		undo_redo->add_undo_method(frames.ptr(), "add_frame", edited_anim, texture, duration);
	}
	undo_redo->add_do_method(this, "_select_animation", new_edited);
	undo_redo->add_undo_method(this, "_select_animation", edited_anim);
	undo_redo->add_do_method(this, "_update_library");
	undo_redo->add_undo_method(this, "_update_library");
	undo_redo->commit_action();
}

void SpriteFramesEditor::_animation_copy() {
	Ref<ClipboardAnimation> clipboard_anim = memnew(ClipboardAnimation);
	clipboard_anim->animation_name = edited_anim;

Review comment (bug):
After cutting or deleting the last animation, an error is displayed:

> ERROR: Animation '' doesn't exist.

It's not your fault, but we have to do something to fix it. CC @TokageItLab If I remember correctly, you once fixed a similar bug.

Code after:
	undo_redo->add_undo_method(frames.ptr(), "remove_animation", new_name);
	undo_redo->add_do_method(this, "_select_animation", new_name);
	undo_redo->add_undo_method(this, "_select_animation", edited_anim);
	undo_redo->add_do_method(this, "_update_library");
	undo_redo->add_undo_method(this, "_update_library");
	undo_redo->commit_action();

	animations->grab_focus();
}

void SpriteFramesEditor::_animation_cut() {
	if (!frames->has_animation(edited_anim)) {
		return;
	}

	// Copy animation to clipboard.
	Ref<ClipboardAnimation> clipboard_anim = ClipboardAnimation::from_sprite_frames(frames, edited_anim);
	EditorSettings::get_singleton()->set_resource_clipboard(clipboard_anim);

	// Remove animation with undo/redo (no confirmation dialog).
	_animation_remove_undo_redo(TTR("Cut Animation"), &clipboard_anim->frames);
}

void SpriteFramesEditor::_animation_copy() {
	if (!frames->has_animation(edited_anim)) {
		return;
	}

	Ref<ClipboardAnimation> clipboard_anim = ClipboardAnimation::from_sprite_frames(frames, edited_anim);
	EditorSettings::get_singleton()->set_resource_clipboard(clipboard_anim);
}

void SpriteFramesEditor::_animation_paste() {
	if (updating) {
		return;
	}

	Ref<ClipboardAnimation> clipboard_anim = EditorSettings::get_singleton()->get_resource_clipboard();
	if (clipboard_anim.is_null()) {
		return;
	}

	String new_name = _generate_unique_animation_name(clipboard_anim->name);
	EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
	undo_redo->create_action(TTR("Paste Animation"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
	undo_redo->add_do_method(frames.ptr(), "add_animation", new_name);
	undo_redo->add_undo_method(frames.ptr(), "remove_animation", new_name);
	undo_redo->add_do_method(frames.ptr(), "set_animation_speed", new_name, clipboard_anim->speed);
	undo_redo->add_do_method(frames.ptr(), "set_animation_loop", new_name, clipboard_anim->loop);

	for (ClipboardSpriteFrames::Frame &frame : clipboard_anim->frames) {