Sequencer file based copy paste #114703
@ -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"
|
||||
|
@ -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
|
||||
|
397
source/blender/editors/space_sequencer/sequencer_clipboard.cc
Normal file
397
source/blender/editors/space_sequencer/sequencer_clipboard.cc
Normal 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");
|
||||
|
||||
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, ¶ms, &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;
|
||||
}
|
@ -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. */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
@ -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);
|
||||
}
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user
“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.