VSE: "Duplicate Strips" also duplicates referenced IDs
Duplicating a strip that references an ID like the scene strip would not
duplicate the scene. This is wanted in some workflows.
To align with the rest of Blender, this changes the behavior for how
strips are duplicated:
* `Shift + D` ("duplicate"): Duplicate the strip and also duplicate the
IDs referenced by the strip. Currently this only affects `Scene`,
`MovieClip`, and `Mask` strips.
* `Alt + D` ("duplicate linked"): Duplicate the strip, but reference the
same IDs. This is the current behavior in `main`.
Part of #144063.
Pull Request: https://projects.blender.org/blender/blender/pulls/144138
This commit is contained in:
@@ -3053,6 +3053,7 @@ def km_sequencer(params):
|
||||
{"properties": [("adjust_length", True)]}),
|
||||
("sequencer.offset_clear", {"type": 'O', "value": 'PRESS', "alt": True}, None),
|
||||
("sequencer.duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
|
||||
("sequencer.duplicate_move_linked", {"type": 'D', "value": 'PRESS', "alt": True}, None),
|
||||
("sequencer.retiming_key_delete", {"type": 'X', "value": 'PRESS'}, None),
|
||||
("sequencer.retiming_key_delete", {"type": 'DEL', "value": 'PRESS'}, None),
|
||||
("sequencer.delete", {"type": 'X', "value": 'PRESS'}, None),
|
||||
@@ -3232,6 +3233,7 @@ def km_sequencer_preview(params):
|
||||
{"properties": [("property", 'ROTATION')]}),
|
||||
|
||||
("sequencer.preview_duplicate_move", {"type": 'D', "value": 'PRESS', "shift": True}, None),
|
||||
("sequencer.preview_duplicate_move_linked", {"type": 'D', "value": 'PRESS', "alt": True}, None),
|
||||
("sequencer.mute", {"type": 'H', "value": 'PRESS'},
|
||||
{"properties": [("unselected", False)]}),
|
||||
("sequencer.mute", {"type": 'H', "value": 'PRESS', "shift": True},
|
||||
|
||||
@@ -1170,6 +1170,7 @@ class SEQUENCER_MT_strip(Menu):
|
||||
layout.operator("sequencer.copy", text="Copy")
|
||||
layout.operator("sequencer.paste", text="Paste")
|
||||
layout.operator("sequencer.duplicate_move", text="Duplicate")
|
||||
layout.operator("sequencer.duplicate_move_linked", text="Duplicate Linked")
|
||||
|
||||
layout.separator()
|
||||
layout.operator("sequencer.delete", text="Delete")
|
||||
|
||||
@@ -334,7 +334,8 @@ static void scene_copy_data(Main *bmain,
|
||||
scene_dst->ed->show_missing_media_flag = scene_src->ed->show_missing_media_flag;
|
||||
scene_dst->ed->proxy_storage = scene_src->ed->proxy_storage;
|
||||
STRNCPY(scene_dst->ed->proxy_dir, scene_src->ed->proxy_dir);
|
||||
blender::seq::seqbase_duplicate_recursive(scene_src,
|
||||
blender::seq::seqbase_duplicate_recursive(bmain,
|
||||
scene_src,
|
||||
scene_dst,
|
||||
&scene_dst->ed->seqbase,
|
||||
&scene_src->ed->seqbase,
|
||||
|
||||
@@ -168,7 +168,8 @@ static bool sequencer_write_copy_paste_file(Main *bmain_src,
|
||||
/* Create an empty sequence editor data to store all copied strips. */
|
||||
scene_dst->ed = MEM_callocN<Editing>(__func__);
|
||||
scene_dst->ed->seqbasep = &scene_dst->ed->seqbase;
|
||||
seq::seqbase_duplicate_recursive(scene_src,
|
||||
seq::seqbase_duplicate_recursive(bmain_src,
|
||||
scene_src,
|
||||
scene_dst,
|
||||
&scene_dst->ed->seqbase,
|
||||
scene_src->ed->seqbasep,
|
||||
@@ -480,8 +481,13 @@ wmOperatorStatus sequencer_clipboard_paste_exec(bContext *C, wmOperator *op)
|
||||
ListBase nseqbase = {nullptr, nullptr};
|
||||
/* NOTE: seq::seqbase_duplicate_recursive() takes care of generating
|
||||
* new UIDs for sequences in the new list. */
|
||||
seq::seqbase_duplicate_recursive(
|
||||
scene_src, scene_dst, &nseqbase, &scene_src->ed->seqbase, seq::StripDuplicate::Selected, 0);
|
||||
seq::seqbase_duplicate_recursive(bmain_dst,
|
||||
scene_src,
|
||||
scene_dst,
|
||||
&nseqbase,
|
||||
&scene_src->ed->seqbase,
|
||||
seq::StripDuplicate::Selected,
|
||||
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.
|
||||
|
||||
@@ -1730,12 +1730,15 @@ void SEQUENCER_OT_split(wmOperatorType *ot)
|
||||
/** \name Duplicate Strips Operator
|
||||
* \{ */
|
||||
|
||||
static wmOperatorStatus sequencer_add_duplicate_exec(bContext *C, wmOperator * /*op*/)
|
||||
static wmOperatorStatus sequencer_add_duplicate_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_sequencer_scene(C);
|
||||
Editing *ed = seq::editing_get(scene);
|
||||
ARegion *region = CTX_wm_region(C);
|
||||
|
||||
const bool linked = RNA_boolean_get(op->ptr, "linked");
|
||||
|
||||
if (ed == nullptr) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
@@ -1755,8 +1758,11 @@ static wmOperatorStatus sequencer_add_duplicate_exec(bContext *C, wmOperator * /
|
||||
}
|
||||
}
|
||||
|
||||
const seq::StripDuplicate dupe_flag = linked ? seq::StripDuplicate::Selected :
|
||||
(seq::StripDuplicate::Selected |
|
||||
seq::StripDuplicate::Data);
|
||||
seq::seqbase_duplicate_recursive(
|
||||
scene, scene, &duplicated_strips, ed->seqbasep, seq::StripDuplicate::Selected, 0);
|
||||
bmain, scene, scene, &duplicated_strips, ed->seqbasep, dupe_flag, 0);
|
||||
deselect_all_strips(scene);
|
||||
|
||||
if (duplicated_strips.first == nullptr) {
|
||||
@@ -1812,6 +1818,8 @@ static wmOperatorStatus sequencer_add_duplicate_exec(bContext *C, wmOperator * /
|
||||
|
||||
void SEQUENCER_OT_duplicate(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* Identifiers. */
|
||||
ot->name = "Duplicate Strips";
|
||||
ot->idname = "SEQUENCER_OT_duplicate";
|
||||
@@ -1823,6 +1831,13 @@ void SEQUENCER_OT_duplicate(wmOperatorType *ot)
|
||||
|
||||
/* Flags. */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
prop = RNA_def_boolean(ot->srna,
|
||||
"linked",
|
||||
false,
|
||||
"Linked",
|
||||
"Duplicate strip but not strip data, linking to the original data");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -1990,6 +2005,7 @@ void SEQUENCER_OT_offset_clear(wmOperatorType *ot)
|
||||
|
||||
static wmOperatorStatus sequencer_separate_images_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Main *bmain = CTX_data_main(C);
|
||||
Scene *scene = CTX_data_sequencer_scene(C);
|
||||
Editing *ed = seq::editing_get(scene);
|
||||
ListBase *seqbase = seq::active_seqbase_get(ed);
|
||||
@@ -2019,7 +2035,7 @@ static wmOperatorStatus sequencer_separate_images_exec(bContext *C, wmOperator *
|
||||
se = seq::render_give_stripelem(scene, strip, timeline_frame);
|
||||
|
||||
strip_new = seq::strip_duplicate_recursive(
|
||||
scene, scene, seqbase, strip, seq::StripDuplicate::UniqueName);
|
||||
bmain, scene, scene, seqbase, strip, seq::StripDuplicate::UniqueName);
|
||||
|
||||
strip_new->start = start_ofs;
|
||||
strip_new->type = STRIP_TYPE_IMAGE;
|
||||
|
||||
@@ -157,23 +157,38 @@ void sequencer_keymap(wmKeyConfig *keyconf)
|
||||
void ED_operatormacros_sequencer()
|
||||
{
|
||||
wmOperatorType *ot;
|
||||
wmOperatorTypeMacro *otmacro;
|
||||
|
||||
ot = WM_operatortype_append_macro("SEQUENCER_OT_duplicate_move",
|
||||
"Duplicate Strips",
|
||||
"Duplicate selected strips and move them",
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
|
||||
WM_operatortype_macro_define(ot, "SEQUENCER_OT_duplicate");
|
||||
WM_operatortype_macro_define(ot, "TRANSFORM_OT_seq_slide");
|
||||
|
||||
ot = WM_operatortype_append_macro("SEQUENCER_OT_duplicate_move_linked",
|
||||
"Duplicate Strips",
|
||||
"Duplicate selected strips, but not their data, and move them",
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
otmacro = WM_operatortype_macro_define(ot, "SEQUENCER_OT_duplicate");
|
||||
RNA_boolean_set(otmacro->ptr, "linked", true);
|
||||
WM_operatortype_macro_define(ot, "TRANSFORM_OT_seq_slide");
|
||||
|
||||
ot = WM_operatortype_append_macro("SEQUENCER_OT_preview_duplicate_move",
|
||||
"Duplicate Strips",
|
||||
"Duplicate selected strips and move them",
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
|
||||
WM_operatortype_macro_define(ot, "SEQUENCER_OT_duplicate");
|
||||
WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
|
||||
|
||||
ot = WM_operatortype_append_macro("SEQUENCER_OT_preview_duplicate_move_linked",
|
||||
"Duplicate Strips",
|
||||
"Duplicate selected strips, but not their data, and move them",
|
||||
OPTYPE_UNDO | OPTYPE_REGISTER);
|
||||
otmacro = WM_operatortype_macro_define(ot, "SEQUENCER_OT_duplicate");
|
||||
RNA_boolean_set(otmacro->ptr, "linked", true);
|
||||
WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate");
|
||||
|
||||
ot = WM_operatortype_append_macro("SEQUENCER_OT_retiming_add_freeze_frame_slide",
|
||||
"Add Freeze Frame And Slide",
|
||||
"Add freeze frame and move it",
|
||||
|
||||
@@ -39,7 +39,11 @@ enum {
|
||||
enum class StripDuplicate : uint8_t {
|
||||
/* Note: Technically, the selected strips are duplicated when `All` is not set. */
|
||||
Selected = 0,
|
||||
/* Ensure strips have a unique name. */
|
||||
UniqueName = (1 << 0),
|
||||
/* Duplicate strips and the IDs they reference. */
|
||||
Data = (1 << 1),
|
||||
/* If this is set, duplicate all strips. If not set, duplicate selected strips. */
|
||||
All = (1 << 3),
|
||||
};
|
||||
ENUM_OPERATORS(StripDuplicate, StripDuplicate::All);
|
||||
@@ -93,12 +97,14 @@ void meta_stack_set(const Scene *scene, Strip *dst);
|
||||
* \param ed: sequence editor data
|
||||
*/
|
||||
Strip *meta_stack_pop(Editing *ed);
|
||||
Strip *strip_duplicate_recursive(const Scene *scene_src,
|
||||
Strip *strip_duplicate_recursive(Main *bmain,
|
||||
const Scene *scene_src,
|
||||
Scene *scene_dst,
|
||||
ListBase *new_seq_list,
|
||||
Strip *strip,
|
||||
StripDuplicate dupe_flag);
|
||||
void seqbase_duplicate_recursive(const Scene *scene_src,
|
||||
void seqbase_duplicate_recursive(Main *bmain,
|
||||
const Scene *scene_src,
|
||||
Scene *scene_dst,
|
||||
ListBase *nseqbase,
|
||||
const ListBase *seqbase,
|
||||
|
||||
@@ -470,7 +470,8 @@ bool proxy_rebuild_context(Main *bmain,
|
||||
|
||||
context = MEM_callocN<IndexBuildContext>("strip proxy rebuild context");
|
||||
|
||||
strip_new = strip_duplicate_recursive(scene, scene, nullptr, strip, StripDuplicate::Selected);
|
||||
strip_new = strip_duplicate_recursive(
|
||||
bmain, scene, scene, nullptr, strip, StripDuplicate::Selected);
|
||||
|
||||
context->tc_flags = strip_new->data->proxy->build_tc_flags;
|
||||
context->size_flags = strip_new->data->proxy->build_size_flags;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "DNA_listBase.h"
|
||||
#include "DNA_mask_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_sequence_types.h"
|
||||
#include "DNA_sound_types.h"
|
||||
@@ -501,7 +502,8 @@ Strip *meta_stack_pop(Editing *ed)
|
||||
/** \name Duplicate Functions
|
||||
* \{ */
|
||||
|
||||
static Strip *strip_duplicate(const Scene *scene_src,
|
||||
static Strip *strip_duplicate(Main *bmain,
|
||||
const Scene *scene_src,
|
||||
Scene *scene_dst,
|
||||
ListBase *new_seq_list,
|
||||
Strip *strip,
|
||||
@@ -564,16 +566,34 @@ static Strip *strip_duplicate(const Scene *scene_src,
|
||||
channels_duplicate(&strip_new->channels, &strip->channels);
|
||||
}
|
||||
else if (strip->type == STRIP_TYPE_SCENE) {
|
||||
if (int(dupe_flag & StripDuplicate::Data) != 0 && strip_new->scene != nullptr) {
|
||||
Scene *scene_old = strip_new->scene;
|
||||
strip_new->scene = BKE_scene_duplicate(bmain, scene_old, SCE_COPY_FULL);
|
||||
}
|
||||
strip_new->data->stripdata = nullptr;
|
||||
if (strip->scene_sound) {
|
||||
strip_new->scene_sound = BKE_sound_scene_add_scene_sound_defaults(scene_dst, strip_new);
|
||||
}
|
||||
}
|
||||
else if (strip->type == STRIP_TYPE_MOVIECLIP) {
|
||||
/* avoid assert */
|
||||
if (int(dupe_flag & StripDuplicate::Data) != 0 && strip_new->clip != nullptr) {
|
||||
MovieClip *clip_old = strip_new->clip;
|
||||
strip_new->clip = reinterpret_cast<MovieClip *>(
|
||||
BKE_id_copy(bmain, reinterpret_cast<ID *>(clip_old)));
|
||||
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT)) {
|
||||
id_us_min(&strip_new->clip->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strip->type == STRIP_TYPE_MASK) {
|
||||
/* avoid assert */
|
||||
if (int(dupe_flag & StripDuplicate::Data) != 0 && strip_new->mask != nullptr) {
|
||||
Mask *mask_old = strip_new->mask;
|
||||
strip_new->mask = reinterpret_cast<Mask *>(
|
||||
BKE_id_copy(bmain, reinterpret_cast<ID *>(mask_old)));
|
||||
if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT)) {
|
||||
id_us_min(&strip_new->mask->id);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (strip->type == STRIP_TYPE_MOVIE) {
|
||||
strip_new->data->stripdata = static_cast<StripElem *>(MEM_dupallocN(strip->data->stripdata));
|
||||
@@ -627,7 +647,8 @@ static Strip *strip_duplicate(const Scene *scene_src,
|
||||
return strip_new;
|
||||
}
|
||||
|
||||
static Strip *strip_duplicate_recursive_impl(const Scene *scene_src,
|
||||
static Strip *strip_duplicate_recursive_impl(Main *bmain,
|
||||
const Scene *scene_src,
|
||||
Scene *scene_dst,
|
||||
ListBase *new_seq_list,
|
||||
Strip *strip,
|
||||
@@ -635,17 +656,18 @@ static Strip *strip_duplicate_recursive_impl(const Scene *scene_src,
|
||||
blender::Map<Strip *, Strip *> &strip_map)
|
||||
{
|
||||
Strip *strip_new = strip_duplicate(
|
||||
scene_src, scene_dst, new_seq_list, strip, dupe_flag, 0, strip_map);
|
||||
bmain, scene_src, scene_dst, new_seq_list, strip, dupe_flag, 0, strip_map);
|
||||
if (strip->type == STRIP_TYPE_META) {
|
||||
LISTBASE_FOREACH (Strip *, s, &strip->seqbase) {
|
||||
strip_duplicate_recursive_impl(
|
||||
scene_src, scene_dst, &strip_new->seqbase, s, dupe_flag, strip_map);
|
||||
bmain, scene_src, scene_dst, &strip_new->seqbase, s, dupe_flag, strip_map);
|
||||
}
|
||||
}
|
||||
return strip_new;
|
||||
}
|
||||
|
||||
Strip *strip_duplicate_recursive(const Scene *scene_src,
|
||||
Strip *strip_duplicate_recursive(Main *bmain,
|
||||
const Scene *scene_src,
|
||||
Scene *scene_dst,
|
||||
ListBase *new_seq_list,
|
||||
Strip *strip,
|
||||
@@ -654,7 +676,7 @@ Strip *strip_duplicate_recursive(const Scene *scene_src,
|
||||
blender::Map<Strip *, Strip *> strip_map;
|
||||
|
||||
Strip *strip_new = strip_duplicate_recursive_impl(
|
||||
scene_src, scene_dst, new_seq_list, strip, dupe_flag, strip_map);
|
||||
bmain, scene_src, scene_dst, new_seq_list, strip, dupe_flag, strip_map);
|
||||
|
||||
seq_new_fix_links_recursive(strip_new, strip_map);
|
||||
if (is_strip_connected(strip_new)) {
|
||||
@@ -664,7 +686,8 @@ Strip *strip_duplicate_recursive(const Scene *scene_src,
|
||||
return strip_new;
|
||||
}
|
||||
|
||||
static void seqbase_dupli_recursive(const Scene *scene_src,
|
||||
static void seqbase_dupli_recursive(Main *bmain,
|
||||
const Scene *scene_src,
|
||||
Scene *scene_dst,
|
||||
ListBase *nseqbase,
|
||||
const ListBase *seqbase,
|
||||
@@ -678,13 +701,14 @@ static void seqbase_dupli_recursive(const Scene *scene_src,
|
||||
}
|
||||
|
||||
Strip *strip_new = strip_duplicate(
|
||||
scene_src, scene_dst, nseqbase, strip, dupe_flag, flag, strip_map);
|
||||
bmain, scene_src, scene_dst, nseqbase, strip, dupe_flag, flag, strip_map);
|
||||
BLI_assert(strip_new != nullptr);
|
||||
|
||||
if (strip->type == STRIP_TYPE_META) {
|
||||
/* Always include meta all strip children. */
|
||||
const StripDuplicate dupe_flag_recursive = dupe_flag | StripDuplicate::All;
|
||||
seqbase_dupli_recursive(scene_src,
|
||||
seqbase_dupli_recursive(bmain,
|
||||
scene_src,
|
||||
scene_dst,
|
||||
&strip_new->seqbase,
|
||||
&strip->seqbase,
|
||||
@@ -695,7 +719,8 @@ static void seqbase_dupli_recursive(const Scene *scene_src,
|
||||
}
|
||||
}
|
||||
|
||||
void seqbase_duplicate_recursive(const Scene *scene_src,
|
||||
void seqbase_duplicate_recursive(Main *bmain,
|
||||
const Scene *scene_src,
|
||||
Scene *scene_dst,
|
||||
ListBase *nseqbase,
|
||||
const ListBase *seqbase,
|
||||
@@ -704,7 +729,8 @@ void seqbase_duplicate_recursive(const Scene *scene_src,
|
||||
{
|
||||
blender::Map<Strip *, Strip *> strip_map;
|
||||
|
||||
seqbase_dupli_recursive(scene_src, scene_dst, nseqbase, seqbase, dupe_flag, flag, strip_map);
|
||||
seqbase_dupli_recursive(
|
||||
bmain, scene_src, scene_dst, nseqbase, seqbase, dupe_flag, flag, strip_map);
|
||||
|
||||
/* Fix effect, modifier, and connected strip links. */
|
||||
LISTBASE_FOREACH (Strip *, strip, nseqbase) {
|
||||
|
||||
@@ -454,7 +454,8 @@ Strip *edit_strip_split(Main *bmain,
|
||||
|
||||
/* Duplicate ListBase. */
|
||||
ListBase right_strips = {nullptr, nullptr};
|
||||
seqbase_duplicate_recursive(scene, scene, &right_strips, &left_strips, StripDuplicate::All, 0);
|
||||
seqbase_duplicate_recursive(
|
||||
bmain, scene, scene, &right_strips, &left_strips, StripDuplicate::All, 0);
|
||||
|
||||
Strip *left_strip = static_cast<Strip *>(left_strips.first);
|
||||
Strip *right_strip = static_cast<Strip *>(right_strips.first);
|
||||
|
||||
Reference in New Issue
Block a user