Fix: VSE: Propagate split to connected strips by default

Currently, attempting to split connected strips that are not both
selected means that only one of the strips are affected.  This violates
the "connected" principle, so this PR makes the split operator propagate
the split to connected strips by default. Holding alt returns old
behavior (ignores connections), similar to selection logic.

Pull Request: https://projects.blender.org/blender/blender/pulls/146380
This commit is contained in:
Ramon Klauck
2025-09-30 18:12:12 +02:00
committed by John Kiril Swenson
parent 1af6ac57f5
commit 412b5b3b3f
6 changed files with 57 additions and 22 deletions

View File

@@ -8628,6 +8628,14 @@ def km_sequencer_tool_blade(_params):
("use_cursor_position", True),
("ignore_selection", True),
]}),
("sequencer.split", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
{"properties": [
("type", 'SOFT'),
("side", 'NO_CHANGE'),
("use_cursor_position", True),
("ignore_selection", True),
("ignore_connections", True),
]}),
]},
)

View File

@@ -1757,6 +1757,7 @@ static wmOperatorStatus sequencer_split_exec(bContext *C, wmOperator *op)
const seq::eSplitMethod method = seq::eSplitMethod(RNA_enum_get(op->ptr, "type"));
const int split_side = sequence_split_side_for_exec_get(op);
const bool ignore_selection = RNA_boolean_get(op->ptr, "ignore_selection");
const bool ignore_connections = RNA_boolean_get(op->ptr, "ignore_connections");
seq::prefetch_stop(scene);
@@ -1767,9 +1768,14 @@ static wmOperatorStatus sequencer_split_exec(bContext *C, wmOperator *op)
if (ignore_selection || strip->flag & SELECT) {
const char *error_msg = nullptr;
if (seq::edit_strip_split(
bmain, scene, ed->current_strips(), strip, split_frame, method, &error_msg) !=
nullptr)
if (seq::edit_strip_split(bmain,
scene,
ed->current_strips(),
strip,
split_frame,
method,
ignore_connections,
&error_msg) != nullptr)
{
changed = true;
}
@@ -1881,6 +1887,10 @@ static void sequencer_split_ui(bContext * /*C*/, wmOperator *op)
if (RNA_boolean_get(op->ptr, "use_cursor_position")) {
layout->prop(op->ptr, "channel", UI_ITEM_NONE, std::nullopt, ICON_NONE);
}
layout->separator();
layout->prop(op->ptr, "ignore_connections", UI_ITEM_NONE, std::nullopt, ICON_NONE);
}
void SEQUENCER_OT_split(wmOperatorType *ot)
@@ -1948,6 +1958,12 @@ void SEQUENCER_OT_split(wmOperatorType *ot)
"Make cut even if strip is not selected preserving selection state after cut");
RNA_def_property_flag(prop, PROP_HIDDEN);
RNA_def_boolean(ot->srna,
"ignore_connections",
false,
"Ignore Connections",
"Don't propagate split to connected strips");
}
/** \} */

View File

@@ -88,15 +88,26 @@ static void rna_Strips_move_strip_to_meta(
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene);
}
static Strip *rna_Strip_split(
ID *id, Strip *strip, Main *bmain, ReportList *reports, int frame, int split_method)
static Strip *rna_Strip_split(ID *id,
Strip *strip,
Main *bmain,
ReportList *reports,
int frame,
int split_method,
bool ignore_connections)
{
Scene *scene = (Scene *)id;
ListBase *seqbase = blender::seq::get_seqbase_by_strip(scene, strip);
const char *error_msg = nullptr;
Strip *strip_split = blender::seq::edit_strip_split(
bmain, scene, seqbase, strip, frame, blender::seq::eSplitMethod(split_method), &error_msg);
Strip *strip_split = blender::seq::edit_strip_split(bmain,
scene,
seqbase,
strip,
frame,
blender::seq::eSplitMethod(split_method),
ignore_connections,
&error_msg);
if (error_msg != nullptr) {
BKE_report(reports, RPT_ERROR, error_msg);
}
@@ -754,6 +765,8 @@ void RNA_api_strip(StructRNA *srna)
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
parm = RNA_def_enum(func, "split_method", strip_split_method_items, 0, "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
parm = RNA_def_boolean(
func, "ignore_connections", false, "", "Don't propagate split to connected strips");
/* Return type. */
parm = RNA_def_pointer(func, "sequence", "Strip", "", "Right side Strip");
RNA_def_function_return(func, parm);

View File

@@ -73,6 +73,7 @@ Strip *edit_strip_split(Main *bmain,
Strip *strip,
int timeline_frame,
eSplitMethod method,
bool ignore_connections,
const char **r_error);
/**
* Find gap after initial_frame and move strips on right side to close the gap

View File

@@ -409,6 +409,7 @@ Strip *edit_strip_split(Main *bmain,
Strip *strip,
const int timeline_frame,
const eSplitMethod method,
const bool ignore_connections,
const char **r_error)
{
if (!seq_edit_split_intersect_check(scene, strip, timeline_frame)) {
@@ -418,21 +419,11 @@ Strip *edit_strip_split(Main *bmain,
/* Whole strip effect chain must be duplicated in order to preserve relationships. */
blender::VectorSet<Strip *> strips;
strips.add(strip);
iterator_set_expand(scene, seqbase, strips, query_strip_effect_chain);
/* All connected strips (that are selected and at the cut frame) must also be duplicated. */
blender::VectorSet<Strip *> strips_old(strips);
for (Strip *strip : strips_old) {
blender::VectorSet<Strip *> connections = connected_strips_get(strip);
connections.remove_if([&](Strip *connection) {
return !(connection->flag & SELECT) ||
!seq_edit_split_intersect_check(scene, connection, timeline_frame);
});
strips.add_multiple(connections.as_span());
}
/* In case connected strips had effects, duplicate those too: */
iterator_set_expand(scene, seqbase, strips, query_strip_effect_chain);
iterator_set_expand(scene,
seqbase,
strips,
ignore_connections ? query_strip_effect_chain :
query_strip_connected_and_effect_chain);
if (!seq_edit_split_operation_permitted_check(scene, strips, timeline_frame, r_error)) {
return nullptr;
@@ -448,6 +439,10 @@ Strip *edit_strip_split(Main *bmain,
BLI_remlink(seqbase, strip_iter);
BLI_addtail(&left_strips, strip_iter);
if (ignore_connections) {
seq::disconnect(strip_iter);
}
/* Duplicate curves from backup, so they can be renamed along with split strips. */
animation_duplicate_backup_to_scene(scene, strip_iter, &animation_backup);
}

View File

@@ -410,6 +410,7 @@ static void strip_transform_handle_overwrite_split(Scene *scene,
target,
time_left_handle_frame_get(scene, transformed),
SPLIT_SOFT,
true,
nullptr);
edit_strip_split(bmain,
scene,
@@ -417,6 +418,7 @@ static void strip_transform_handle_overwrite_split(Scene *scene,
split_strip,
time_right_handle_frame_get(scene, transformed),
SPLIT_SOFT,
true,
nullptr);
edit_flag_for_removal(scene, seqbasep, split_strip);
edit_remove_flagged_strips(scene, seqbasep);