Sequencer file based copy paste #114703

Merged
Sebastian Parborg merged 18 commits from ZedDB/blender:copy_paste into main 2023-12-07 15:40:01 +01:00
9 changed files with 406 additions and 437 deletions

View File

@ -99,7 +99,6 @@
#include "BLO_readfile.h"
#include "BLO_undofile.hh"
#include "SEQ_clipboard.hh"
#include "SEQ_iterator.hh"
#include "SEQ_modifier.hh"
#include "SEQ_sequencer.hh"

View File

@ -25,6 +25,7 @@ set(SRC
sequencer_buttons.cc
sequencer_channels_draw.cc
sequencer_channels_edit.cc
sequencer_clipboard.cc
sequencer_drag_drop.cc
sequencer_edit.cc
sequencer_modifier.cc

View File

@ -0,0 +1,397 @@
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
* SPDX-FileCopyrightText: 2003-2009 Blender Authors
* SPDX-FileCopyrightText: 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de>
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*/
#include <cstring>
#include "BLO_readfile.h"
#include "MEM_guardedalloc.h"
#include "ED_keyframing.hh"
#include "ED_outliner.hh"
#include "ED_sequencer.hh"
#include "DNA_anim_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_space_types.h"
#include "DNA_windowmanager_types.h"
#include "BLI_ghash.h"
#include "BLI_listbase.h"
#include "BLI_path_util.h"
#include "BKE_appdir.h"
#include "BKE_blender_copybuffer.h"
#include "BKE_blendfile.h"
#include "BKE_context.hh"
#include "BKE_fcurve.h"
#include "BKE_lib_id.h"
#include "BKE_lib_query.h"
#include "BKE_lib_remap.hh"
#include "BKE_main.hh"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "RNA_access.hh"
#include "SEQ_animation.hh"
#include "SEQ_select.hh"
#include "SEQ_sequencer.hh"
#include "SEQ_time.hh"
#include "SEQ_transform.hh"
#include "SEQ_utils.hh"
#include "DEG_depsgraph.hh"
#include "DEG_depsgraph_build.hh"
#include "WM_api.hh"
#include "WM_types.hh"
#ifdef WITH_AUDASPACE
# include <AUD_Special.h>
#endif
/* Own include. */
#include "sequencer_intern.hh"
/* -------------------------------------------------------------------- */
/* Copy Operator Helper functions
*/
static int gather_strip_data_ids_to_null(LibraryIDLinkCallbackData *cb_data)
{
IDRemapper *id_remapper = static_cast<IDRemapper *>(cb_data->user_data);
ID *id = *cb_data->id_pointer;
/* We don't care about embedded, loopback, or internal IDs. */
if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_EMBEDDED_NOT_OWNING)) {
return IDWALK_RET_NOP;
}
if (cb_data->cb_flag & (IDWALK_CB_LOOPBACK | IDWALK_CB_INTERNAL)) {
return IDWALK_RET_STOP_RECURSION;
}
if (id) {
ID_Type id_type = GS((id)->name);
/* Nullify everything that is not:
* Sound, Movieclip, Image, Text, Vfont, Action, or Collection IDs.
*/
if (!ELEM(id_type, ID_SO, ID_MC, ID_IM, ID_TXT, ID_VF, ID_AC)) {
BKE_id_remapper_add(id_remapper, id, nullptr);
return IDWALK_RET_STOP_RECURSION;
}
}
return IDWALK_RET_NOP;
}
static void sequencer_copy_animation_listbase(Scene *scene_src,
Sequence *seq_dst,
ListBase *clipboard_dst,
ListBase *fcurve_base_src)
{
/* Add curves for strips inside meta strip. */
if (seq_dst->type == SEQ_TYPE_META) {
LISTBASE_FOREACH (Sequence *, meta_child, &seq_dst->seqbase) {
sequencer_copy_animation_listbase(scene_src, meta_child, clipboard_dst, fcurve_base_src);
}
}
GSet *fcurves_src = SEQ_fcurves_by_strip_get(seq_dst, fcurve_base_src);
if (fcurves_src == nullptr) {
return;
}
GSET_FOREACH_BEGIN (FCurve *, fcu_src, fcurves_src) {
BLI_addtail(clipboard_dst, BKE_fcurve_copy(fcu_src));
}
GSET_FOREACH_END();
BLI_gset_free(fcurves_src, nullptr);
}
static void sequencer_copy_animation(Scene *scene_src,
ListBase *fcurves_dst,
ListBase *drivers_dst,
Sequence *seq_dst)
{
if (SEQ_animation_curves_exist(scene_src)) {
sequencer_copy_animation_listbase(
scene_src, seq_dst, fcurves_dst, &scene_src->adt->action->curves);
}
if (SEQ_animation_drivers_exist(scene_src)) {
sequencer_copy_animation_listbase(scene_src, seq_dst, drivers_dst, &scene_src->adt->drivers);
}
}
static void sequencer_copybuffer_filepath_get(char filepath[FILE_MAX], size_t filepath_maxncpy)
{
BLI_path_join(filepath, filepath_maxncpy, BKE_tempdir_base(), "copybuffer_vse.blend");
}
static bool sequencer_write_copy_paste_file(Main *bmain_src,
Scene *scene_src,
const char *filepath,
ReportList *reports)
{
/* Ideally, scene should not be added to the global Main. There currently is no good
* solution to avoid it if we want to properly pull in all strip dependecies. */
Scene *scene_dst = BKE_scene_add(bmain_src, "copybuffer_vse_scene");
/* Create a temporary scene that we will copy from.
* This is needed as it is the scene that contains all the VSE strip data.
*/
scene_dst->ed = MEM_cnew<Editing>(__func__);
scene_dst->ed->seqbasep = &scene_dst->ed->seqbase;
SEQ_sequence_base_dupli_recursive(
scene_src, scene_dst, &scene_dst->ed->seqbase, &scene_src->ed->seqbase, 0, 0);
BLI_duplicatelist(&scene_dst->ed->channels, &scene_src->ed->channels);
scene_dst->ed->displayed_channels = &scene_dst->ed->channels;
/* Save current frame and active strip. */
scene_dst->r.cfra = scene_src->r.cfra;
Sequence *active_seq_src = SEQ_select_active_get(scene_src);
if (active_seq_src) {
Sequence *seq_dst = static_cast<Sequence *>(
BLI_findstring(&scene_dst->ed->seqbase, active_seq_src->name, offsetof(Sequence, name)));
if (seq_dst) {
SEQ_select_active_set(scene_dst, seq_dst);
}
}
ListBase fcurves_dst = {nullptr, nullptr};
ListBase drivers_dst = {nullptr, nullptr};
LISTBASE_FOREACH (Sequence *, seq_dst, &scene_dst->ed->seqbase) {
/* Copy animation curves from seq_dst (if any). */
sequencer_copy_animation(scene_src, &fcurves_dst, &drivers_dst, seq_dst);
}
if (!BLI_listbase_is_empty(&fcurves_dst) || !BLI_listbase_is_empty(&drivers_dst)) {
BLI_assert(scene_dst->adt == nullptr);
bAction *act_dst = ED_id_action_ensure(bmain_src, &scene_dst->id);
BLI_movelisttolist(&act_dst->curves, &fcurves_dst);
BLI_movelisttolist(&scene_dst->adt->drivers, &drivers_dst);
}
/* Nullify all ID pointers that we don't want to copy. For example, we don't want
* to copy whole scenes. We have to come up with a proper idea of how to copy and
* paste scene strips.
*/
IDRemapper *id_remapper = BKE_id_remapper_create();
BKE_library_foreach_ID_link(
bmain_src, &scene_dst->id, gather_strip_data_ids_to_null, id_remapper, IDWALK_RECURSE);
BKE_libblock_remap_multiple(bmain_src, id_remapper, 0);
BKE_id_remapper_free(id_remapper);
/* Ensure that there are no old copy tags around */
BKE_blendfile_write_partial_begin(bmain_src);
/* Tag the scene copy so we can pull in all scrip deps */
BKE_copybuffer_copy_tag_ID(&scene_dst->id);
/* Create the copy/paste temp file */
bool retval = BKE_copybuffer_copy_end(bmain_src, filepath, reports);
/* Clean up the action ID if we created any. */
if (scene_dst->adt != nullptr && scene_dst->adt->action != nullptr) {
BKE_id_delete(bmain_src, scene_dst->adt->action);
}
/* Cleanup the dummy scene file */
BKE_id_delete(bmain_src, scene_dst);
return retval;
}
int sequencer_clipboard_copy_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
if (SEQ_transform_seqbase_isolated_sel_check(ed->seqbasep) == false) {
BKE_report(op->reports, RPT_ERROR, "Please select all related strips");
return OPERATOR_CANCELLED;
}
char filepath[FILE_MAX];
sequencer_copybuffer_filepath_get(filepath, sizeof(filepath));
bool success = sequencer_write_copy_paste_file(bmain, scene, filepath, op->reports);
if (!success) {
BKE_report(op->reports, RPT_ERROR, "Could not create the copy paste file!");
return OPERATOR_CANCELLED;
}
/* We are all done! */
BKE_report(op->reports, RPT_INFO, "Copied the selected VSE strips to internal clipboard");
Review

“VSE” is mentioned nowhere in Blender’s UI, and nowhere in the manual except to describe options from an add-on.

I think it should be called “Sequencer” for consistency with the rest of the UI.

Same on line 294.

“VSE” is mentioned nowhere in Blender’s UI, and nowhere in the manual except to describe options from an add-on. I think it should be called “Sequencer” for consistency with the rest of the UI. Same on line 294.
return OPERATOR_FINISHED;
}
/* -------------------------------------------------------------------- */
/* Paste Operator Helper functions
*/
static bool sequencer_paste_animation(Main *bmain_dst, Scene *scene_dst, Scene *scene_src)
{
if (!SEQ_animation_curves_exist(scene_src) && !SEQ_animation_drivers_exist(scene_src)) {
return false;
}
bAction *act_dst;
if (scene_dst->adt != nullptr && scene_dst->adt->action != nullptr) {
act_dst = scene_dst->adt->action;
}
else {
/* get action to add F-Curve+keyframe to */
act_dst = ED_id_action_ensure(bmain_dst, &scene_dst->id);
}
LISTBASE_FOREACH (FCurve *, fcu, &scene_src->adt->action->curves) {
BLI_addtail(&act_dst->curves, BKE_fcurve_copy(fcu));
}
LISTBASE_FOREACH (FCurve *, fcu, &scene_src->adt->drivers) {
BLI_addtail(&scene_dst->adt->drivers, BKE_fcurve_copy(fcu));
}
return true;
}
int sequencer_clipboard_paste_exec(bContext *C, wmOperator *op)
{
char filepath[FILE_MAX];
sequencer_copybuffer_filepath_get(filepath, sizeof(filepath));
const BlendFileReadParams params{};
BlendFileReadReport bf_reports{};
BlendFileData *bfd = BKE_blendfile_read(filepath, &params, &bf_reports);
if (bfd == nullptr) {
BKE_report(op->reports, RPT_INFO, "No data to paste");
return OPERATOR_CANCELLED;
}
Main *bmain_src = bfd->main;
bfd->main = nullptr;
BLO_blendfiledata_free(bfd);
Scene *scene_src = nullptr;
/* Find the scene we pasted that contains the strips. It should be tagged. */
LISTBASE_FOREACH (Scene *, scene_iter, &bmain_src->scenes) {
if (scene_iter->id.flag & LIB_CLIPBOARD_MARK) {
scene_src = scene_iter;
break;
}
}
if (!scene_src || !scene_src->ed) {
BKE_report(op->reports, RPT_ERROR, "No clipboard scene to paste VSE data from");
BKE_main_free(bmain_src);
return OPERATOR_CANCELLED;
}
const int num_strips_to_paste = BLI_listbase_count(&scene_src->ed->seqbase);
if (num_strips_to_paste == 0) {
BKE_report(op->reports, RPT_INFO, "No strips to paste");
BKE_main_free(bmain_src);
return OPERATOR_CANCELLED;
}
Scene *scene_dst = CTX_data_scene(C);
Editing *ed_dst = SEQ_editing_ensure(scene_dst); /* Creates "ed" if it's missing. */
int ofs;
ED_sequencer_deselect_all(scene_dst);
if (RNA_boolean_get(op->ptr, "keep_offset")) {
ofs = scene_dst->r.cfra - scene_src->r.cfra;
}
else {
int min_seq_startdisp = INT_MAX;
LISTBASE_FOREACH (Sequence *, seq, &scene_src->ed->seqbase) {
if (SEQ_time_left_handle_frame_get(scene_src, seq) < min_seq_startdisp) {
min_seq_startdisp = SEQ_time_left_handle_frame_get(scene_src, seq);
}
}
/* Paste strips relative to the current-frame. */
ofs = scene_dst->r.cfra - min_seq_startdisp;
}
Sequence *prev_active_seq = SEQ_select_active_get(scene_src);
std::string active_seq_name;
if (prev_active_seq) {
active_seq_name.assign(prev_active_seq->name);
}
/* Make sure we have all data IDs we need in bmain_dst. Remap the IDs if we already have them.
* This has to happen BEFORE we move the strip over to scene_dst. their ID mapping will not be
* correct otherwise. */
Main *bmain_dst = CTX_data_main(C);
MainMergeReport merge_reports = {};
/* NOTE: BKE_main_merge will free bmain_src! */
BKE_main_merge(bmain_dst, &bmain_src, merge_reports);
/* Paste animation.
* NOTE: Only fcurves and drivers are copied. NLA action strips are not copied.
* First backup original curves from scene and move curves from clipboard into scene. This way,
* when pasted strips are renamed, pasted fcurves are renamed with them. Finally restore original
* curves from backup.
*/
SeqAnimationBackup animation_backup = {{nullptr}};
SEQ_animation_backup_original(scene_dst, &animation_backup);
bool has_animation = sequencer_paste_animation(bmain_dst, scene_dst, scene_src);
ListBase nseqbase = {nullptr, nullptr};
/* NOTE: SEQ_sequence_base_dupli_recursive() takes care of generating
* new UUIDs for sequences in the new list. */
SEQ_sequence_base_dupli_recursive(
scene_src, scene_dst, &nseqbase, &scene_src->ed->seqbase, 0, 0);
/* BKE_main_merge will copy the scene_src and its action into bmain_dst. Remove them as
* we merge the data from these manually.
*/
if (has_animation) {
BKE_id_delete(bmain_dst, scene_src->adt->action);
}
BKE_id_delete(bmain_dst, scene_src);
Sequence *iseq_first = static_cast<Sequence *>(nseqbase.first);
BLI_movelisttolist(ed_dst->seqbasep, &nseqbase);
/* Restore "first" pointer as BLI_movelisttolist sets it to nullptr */
nseqbase.first = iseq_first;
LISTBASE_FOREACH (Sequence *, iseq, &nseqbase) {
if (STREQ(iseq->name, active_seq_name.c_str())) {
SEQ_select_active_set(scene_dst, iseq);
}
/* Make sure, that pasted strips have unique names. This has to be done after
* adding strips to seqbase, for lookup cache to work correctly. */
SEQ_ensure_unique_name(iseq, scene_dst);
}
LISTBASE_FOREACH (Sequence *, iseq, &nseqbase) {
/* Translate after name has been changed, otherwise this will affect animdata of original
* strip. */
SEQ_transform_translate_sequence(scene_dst, iseq, ofs);
/* Ensure, that pasted strips don't overlap. */
if (SEQ_transform_test_overlap(scene_dst, ed_dst->seqbasep, iseq)) {
SEQ_transform_seqbase_shuffle(ed_dst->seqbasep, iseq, scene_dst);
}
}
SEQ_animation_restore_original(scene_dst, &animation_backup);
DEG_id_tag_update(&scene_dst->id, ID_RECALC_SEQUENCER_STRIPS);
DEG_relations_tag_update(bmain_dst);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene_dst);
ED_outliner_select_sync_from_sequence_tag(C);
BKE_reportf(op->reports, RPT_INFO, "%d strips pasted", num_strips_to_paste);
return OPERATOR_FINISHED;
}

View File

@ -6,15 +6,11 @@
* \ingroup spseq
*/
#include <cmath>
#include <cstdlib>
#include <cstring>
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "BLI_ghash.h"
#include "BLI_fileops.h"
#include "BLI_math_vector.h"
#include "BLI_path_util.h"
#include "BLI_string.h"
#include "BLI_timecode.h"
#include "BLI_utildefines.h"
@ -28,7 +24,6 @@
#include "BKE_context.hh"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_lib_id.h"
#include "BKE_main.hh"
#include "BKE_report.h"
#include "BKE_sound.h"
@ -36,7 +31,6 @@
#include "SEQ_add.hh"
#include "SEQ_animation.hh"
#include "SEQ_channels.hh"
#include "SEQ_clipboard.hh"
#include "SEQ_edit.hh"
#include "SEQ_effects.hh"
#include "SEQ_iterator.hh"
@ -58,9 +52,7 @@
/* For menu, popup, icons, etc. */
#include "ED_fileselect.hh"
#include "ED_keyframing.hh"
#include "ED_numinput.hh"
#include "ED_outliner.hh"
#include "ED_scene.hh"
#include "ED_screen.hh"
#include "ED_sequencer.hh"
@ -2458,94 +2450,6 @@ void SEQUENCER_OT_rendersize(wmOperatorType *ot)
/** \name Copy Operator
* \{ */
static void seq_copy_del_sound(Scene *scene, Sequence *seq)
{
if (seq->type == SEQ_TYPE_META) {
LISTBASE_FOREACH (Sequence *, iseq, &seq->seqbase) {
seq_copy_del_sound(scene, iseq);
}
}
else if (seq->scene_sound) {
BKE_sound_remove_scene_sound(scene, seq->scene_sound);
seq->scene_sound = nullptr;
}
}
static void sequencer_copy_animation_listbase(Scene *scene,
Sequence *seq,
ListBase *clipboard,
ListBase *fcurve_base)
{
/* Add curves for strips inside meta strip. */
if (seq->type == SEQ_TYPE_META) {
LISTBASE_FOREACH (Sequence *, meta_child, &seq->seqbase) {
sequencer_copy_animation_listbase(scene, meta_child, clipboard, fcurve_base);
}
}
GSet *fcurves = SEQ_fcurves_by_strip_get(seq, fcurve_base);
if (fcurves == nullptr) {
return;
}
GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) {
BLI_addtail(clipboard, BKE_fcurve_copy(fcu));
}
GSET_FOREACH_END();
BLI_gset_free(fcurves, nullptr);
}
static void sequencer_copy_animation(Scene *scene, Sequence *seq)
{
if (SEQ_animation_curves_exist(scene)) {
sequencer_copy_animation_listbase(scene, seq, &fcurves_clipboard, &scene->adt->action->curves);
}
if (SEQ_animation_drivers_exist(scene)) {
sequencer_copy_animation_listbase(scene, seq, &drivers_clipboard, &scene->adt->drivers);
}
}
static int sequencer_copy_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
SEQ_clipboard_free();
if (SEQ_transform_seqbase_isolated_sel_check(ed->seqbasep) == false) {
BKE_report(op->reports, RPT_ERROR, "Please select all related strips");
return OPERATOR_CANCELLED;
}
/* NOTE: The UUID is re-generated on paste, so we can keep UUID in the clipboard since
* nobody can reach them anyway.
* This reduces chance or running out of UUIDs if a cat falls asleep on Ctrl-C. */
SEQ_sequence_base_dupli_recursive(scene,
scene,
&seqbase_clipboard,
ed->seqbasep,
0,
(LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_FREE_NO_MAIN));
seqbase_clipboard_frame = scene->r.cfra;
SEQ_clipboard_active_seq_name_store(scene);
LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
/* Copy curves. */
sequencer_copy_animation(scene, seq);
/* Remove anything that references the current scene. */
seq_copy_del_sound(scene, seq);
}
/* Replace datablock pointers with copies, to keep things working in case
* data-blocks get deleted or another .blend file is opened. */
SEQ_clipboard_pointers_store(bmain, &seqbase_clipboard);
return OPERATOR_FINISHED;
}
void SEQUENCER_OT_copy(wmOperatorType *ot)
{
/* Identifiers. */
@ -2554,7 +2458,7 @@ void SEQUENCER_OT_copy(wmOperatorType *ot)
ot->description = "Copy the selected strips to the internal clipboard";
/* Api callbacks. */
ot->exec = sequencer_copy_exec;
ot->exec = sequencer_clipboard_copy_exec;
ot->poll = sequencer_edit_poll;
/* Flags. */
@ -2585,114 +2489,6 @@ bool ED_sequencer_deselect_all(Scene *scene)
return changed;
}
static void sequencer_paste_animation(bContext *C)
{
if (BLI_listbase_is_empty(&fcurves_clipboard) && BLI_listbase_is_empty(&drivers_clipboard)) {
return;
}
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
bAction *act;
if (scene->adt != nullptr && scene->adt->action != nullptr) {
act = scene->adt->action;
}
else {
/* get action to add F-Curve+keyframe to */
act = ED_id_action_ensure(bmain, &scene->id);
}
LISTBASE_FOREACH (FCurve *, fcu, &fcurves_clipboard) {
BLI_addtail(&act->curves, BKE_fcurve_copy(fcu));
}
LISTBASE_FOREACH (FCurve *, fcu, &drivers_clipboard) {
BLI_addtail(&scene->adt->drivers, BKE_fcurve_copy(fcu));
}
}
static int sequencer_paste_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_ensure(scene); /* Create if needed. */
ListBase nseqbase = {nullptr, nullptr};
int ofs;
Sequence *iseq, *iseq_first;
if (BLI_listbase_count(&seqbase_clipboard) == 0) {
BKE_report(op->reports, RPT_INFO, "No strips to paste");
return OPERATOR_CANCELLED;
}
ED_sequencer_deselect_all(scene);
if (RNA_boolean_get(op->ptr, "keep_offset")) {
ofs = scene->r.cfra - seqbase_clipboard_frame;
}
else {
int min_seq_startdisp = INT_MAX;
LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) {
if (SEQ_time_left_handle_frame_get(scene, seq) < min_seq_startdisp) {
min_seq_startdisp = SEQ_time_left_handle_frame_get(scene, seq);
}
}
/* Paste strips relative to the current-frame. */
ofs = scene->r.cfra - min_seq_startdisp;
}
/* Paste animation.
* NOTE: Only fcurves are copied. Drivers and NLA action strips are not copied.
* First backup original curves from scene and move curves from clipboard into scene. This way,
* when pasted strips are renamed, pasted fcurves are renamed with them. Finally restore original
* curves from backup.
*/
SeqAnimationBackup animation_backup = {{nullptr}};
SEQ_animation_backup_original(scene, &animation_backup);
sequencer_paste_animation(C);
/* Copy strips, temporarily restoring pointers to actual data-blocks. This
* must happen on the clipboard itself, so that copying does user counting
* on the actual data-blocks. */
SEQ_clipboard_pointers_restore(&seqbase_clipboard, bmain);
SEQ_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, 0, 0);
SEQ_clipboard_pointers_store(bmain, &seqbase_clipboard);
iseq_first = static_cast<Sequence *>(nseqbase.first);
/* NOTE: SEQ_sequence_base_dupli_recursive() takes care of generating new UUIDs for sequences
* in the new list. */
BLI_movelisttolist(ed->seqbasep, &nseqbase);
for (iseq = iseq_first; iseq; iseq = iseq->next) {
if (SEQ_clipboard_pasted_seq_was_active(iseq)) {
SEQ_select_active_set(scene, iseq);
}
/* Make sure, that pasted strips have unique names. This has to be done after
* adding strips to seqbase, for lookup cache to work correctly. */
SEQ_ensure_unique_name(iseq, scene);
}
for (iseq = iseq_first; iseq; iseq = iseq->next) {
/* Translate after name has been changed, otherwise this will affect animdata of original
* strip. */
SEQ_transform_translate_sequence(scene, iseq, ofs);
/* Ensure, that pasted strips don't overlap. */
if (SEQ_transform_test_overlap(scene, ed->seqbasep, iseq)) {
SEQ_transform_seqbase_shuffle(ed->seqbasep, iseq, scene);
}
}
SEQ_animation_restore_original(scene, &animation_backup);
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
DEG_relations_tag_update(bmain);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
ED_outliner_select_sync_from_sequence_tag(C);
return OPERATOR_FINISHED;
}
void SEQUENCER_OT_paste(wmOperatorType *ot)
{
/* Identifiers. */
@ -2701,7 +2497,7 @@ void SEQUENCER_OT_paste(wmOperatorType *ot)
ot->description = "Paste strips from the internal clipboard";
/* Api callbacks. */
ot->exec = sequencer_paste_exec;
ot->exec = sequencer_clipboard_paste_exec;
ot->poll = ED_operator_sequencer_active;
/* Flags. */

View File

@ -326,3 +326,7 @@ SeqRetimingKey *retiming_mousover_key_get(const bContext *C, const int mval[2],
int left_fake_key_frame_get(const bContext *C, const Sequence *seq);
int right_fake_key_frame_get(const bContext *C, const Sequence *seq);
bool retiming_keys_are_visible(const bContext *C);
/* `sequencer_clipboard.cc` */
int sequencer_clipboard_copy_exec(bContext *C, wmOperator *op);
int sequencer_clipboard_paste_exec(bContext *C, wmOperator *op);

View File

@ -24,7 +24,6 @@ set(SRC
SEQ_add.hh
SEQ_animation.hh
SEQ_channels.hh
SEQ_clipboard.hh
SEQ_edit.hh
SEQ_effects.hh
SEQ_iterator.hh
@ -43,7 +42,6 @@ set(SRC
intern/animation.cc
intern/channels.cc
intern/clipboard.cc
intern/disk_cache.cc
intern/disk_cache.hh
intern/effects.cc

View File

@ -1,31 +0,0 @@
/* SPDX-FileCopyrightText: 2004 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup sequencer
*/
struct ListBase;
struct Main;
struct Scene;
struct Sequence;
extern ListBase seqbase_clipboard;
extern ListBase fcurves_clipboard;
extern ListBase drivers_clipboard;
extern int seqbase_clipboard_frame;
void SEQ_clipboard_pointers_store(Main *bmain, ListBase *seqbase);
void SEQ_clipboard_pointers_restore(ListBase *seqbase, Main *bmain);
void SEQ_clipboard_free();
void SEQ_clipboard_active_seq_name_store(Scene *scene);
/**
* Check if strip was active when it was copied. User should restrict this check to pasted strips
* before ensuring original name, because strip name comparison is used to check.
*
* \param pasted_seq: Strip that is pasted(duplicated) from clipboard
* \return true if strip was active, false otherwise
*/
bool SEQ_clipboard_pasted_seq_was_active(Sequence *pasted_seq);

View File

@ -1,192 +0,0 @@
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
* SPDX-FileCopyrightText: 2003-2009 Blender Authors
* SPDX-FileCopyrightText: 2005-2006 Peter Schlaile <peter [at] schlaile [dot] de>
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*/
#include <cstring>
#include "MEM_guardedalloc.h"
#include "DNA_anim_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
#include "DNA_sound_types.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BKE_fcurve.h"
#include "BKE_main.hh"
#include "BKE_movieclip.h"
#include "BKE_scene.h"
#include "BKE_sound.h"
#include "SEQ_clipboard.hh"
#include "SEQ_select.hh"
#include "sequencer.hh"
#ifdef WITH_AUDASPACE
# include <AUD_Special.h>
#endif
/* -------------------------------------------------------------------- */
/* Manage pointers in the clipboard.
* note that these pointers should _never_ be access in the sequencer,
* they are only for storage while in the clipboard
* notice 'newid' is used for temp pointer storage here, validate on access (this is safe usage,
* since those data-blocks are fully out of Main lists).
*/
ListBase seqbase_clipboard;
ListBase fcurves_clipboard;
ListBase drivers_clipboard;
int seqbase_clipboard_frame;
static char seq_clipboard_active_seq_name[SEQ_NAME_MAXSTR];
void seq_clipboard_pointers_free(ListBase *seqbase);
void SEQ_clipboard_free()
{
seq_clipboard_pointers_free(&seqbase_clipboard);
LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqbase_clipboard) {
seq_free_sequence_recurse(nullptr, seq, false);
}
BLI_listbase_clear(&seqbase_clipboard);
LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &fcurves_clipboard) {
BKE_fcurve_free(fcu);
}
BLI_listbase_clear(&fcurves_clipboard);
LISTBASE_FOREACH_MUTABLE (FCurve *, fcu, &drivers_clipboard) {
BKE_fcurve_free(fcu);
}
BLI_listbase_clear(&drivers_clipboard);
}
#define ID_PT (*id_pt)
static void seqclipboard_ptr_free(Main * /*bmain*/, ID **id_pt)
{
if (ID_PT) {
BLI_assert(ID_PT->newid != nullptr);
MEM_freeN(ID_PT);
ID_PT = nullptr;
}
}
static void seqclipboard_ptr_store(Main * /*bmain*/, ID **id_pt)
{
if (ID_PT) {
ID *id_prev = ID_PT;
ID_PT = static_cast<ID *>(MEM_dupallocN(ID_PT));
ID_PT->newid = id_prev;
}
}
static void seqclipboard_ptr_restore(Main *bmain, ID **id_pt)
{
if (ID_PT) {
const ListBase *lb = which_libbase(bmain, GS(ID_PT->name));
void *id_restore;
BLI_assert(ID_PT->newid != nullptr);
if (BLI_findindex(lb, (ID_PT)->newid) != -1) {
/* the pointer is still valid */
id_restore = (ID_PT)->newid;
}
else {
/* The pointer of the same name still exists. */
id_restore = BLI_findstring(lb, (ID_PT)->name + 2, offsetof(ID, name) + 2);
}
if (id_restore == nullptr) {
/* check for a data with the same filename */
switch (GS(ID_PT->name)) {
case ID_SO: {
id_restore = BLI_findstring(lb, ((bSound *)ID_PT)->filepath, offsetof(bSound, filepath));
if (id_restore == nullptr) {
id_restore = BKE_sound_new_file(bmain, ((bSound *)ID_PT)->filepath);
(ID_PT)->newid = static_cast<ID *>(id_restore); /* reuse next time */
}
break;
}
case ID_MC: {
id_restore = BLI_findstring(
lb, ((MovieClip *)ID_PT)->filepath, offsetof(MovieClip, filepath));
if (id_restore == nullptr) {
id_restore = BKE_movieclip_file_add(bmain, ((MovieClip *)ID_PT)->filepath);
(ID_PT)->newid = static_cast<ID *>(id_restore); /* reuse next time */
}
break;
}
default:
break;
}
}
/* Replace with pointer to actual data-block. */
seqclipboard_ptr_free(bmain, id_pt);
ID_PT = static_cast<ID *>(id_restore);
}
}
#undef ID_PT
static void sequence_clipboard_pointers(Main *bmain,
Sequence *seq,
void (*callback)(Main *, ID **))
{
callback(bmain, (ID **)&seq->scene);
callback(bmain, (ID **)&seq->scene_camera);
callback(bmain, (ID **)&seq->clip);
callback(bmain, (ID **)&seq->mask);
callback(bmain, (ID **)&seq->sound);
if (seq->type == SEQ_TYPE_TEXT && seq->effectdata) {
TextVars *text_data = static_cast<TextVars *>(seq->effectdata);
callback(bmain, (ID **)&text_data->text_font);
}
}
/* recursive versions of functions above */
void seq_clipboard_pointers_free(ListBase *seqbase)
{
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
sequence_clipboard_pointers(nullptr, seq, seqclipboard_ptr_free);
seq_clipboard_pointers_free(&seq->seqbase);
}
}
void SEQ_clipboard_pointers_store(Main *bmain, ListBase *seqbase)
{
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_store);
SEQ_clipboard_pointers_store(bmain, &seq->seqbase);
}
}
void SEQ_clipboard_pointers_restore(ListBase *seqbase, Main *bmain)
{
LISTBASE_FOREACH (Sequence *, seq, seqbase) {
sequence_clipboard_pointers(bmain, seq, seqclipboard_ptr_restore);
SEQ_clipboard_pointers_restore(&seq->seqbase, bmain);
}
}
void SEQ_clipboard_active_seq_name_store(Scene *scene)
{
Sequence *active_seq = SEQ_select_active_get(scene);
if (active_seq != nullptr) {
STRNCPY(seq_clipboard_active_seq_name, active_seq->name);
}
else {
seq_clipboard_active_seq_name[0] = '\0';
}
}
bool SEQ_clipboard_pasted_seq_was_active(Sequence *pasted_seq)
{
return STREQ(pasted_seq->name, seq_clipboard_active_seq_name);
}

View File

@ -63,8 +63,6 @@
#include "RE_engine.h"
#include "RE_pipeline.h" /* RE_ free stuff */
#include "SEQ_clipboard.hh" /* free seq clipboard */
#include "IMB_thumbs.h"
#ifdef WITH_PYTHON
@ -581,7 +579,6 @@ void WM_exit_ex(bContext *C, const bool do_python_exit, const bool do_user_exit_
ED_preview_restart_queue_free();
ED_assetlist_storage_exit();
SEQ_clipboard_free(); /* `sequencer.cc` */
BKE_tracking_clipboard_free();
BKE_mask_clipboard_free();
BKE_vfont_clipboard_free();