Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/space_sequencer/sequencer_select.c')
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c259
1 files changed, 189 insertions, 70 deletions
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index b4271ebd812..8a8a24f08ff 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -25,6 +25,8 @@
#include <stdlib.h>
#include <string.h>
+#include "MEM_guardedalloc.h"
+
#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
@@ -414,9 +416,17 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
+ const bool is_preview = sequencer_view_preview_poll(C);
+ if (is_preview) {
+ SEQ_query_rendered_strips_to_tag(ed->seqbasep, scene->r.cfra, 0);
+ }
+
if (action == SEL_TOGGLE) {
action = SEL_SELECT;
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (seq->flag & SEQ_ALLSEL) {
action = SEL_DESELECT;
break;
@@ -425,6 +435,9 @@ static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
}
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
switch (action) {
case SEL_SELECT:
seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
@@ -481,7 +494,15 @@ static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
Editing *ed = SEQ_editing_get(scene);
Sequence *seq;
+ const bool is_preview = sequencer_view_preview_poll(C);
+ if (is_preview) {
+ SEQ_query_rendered_strips_to_tag(ed->seqbasep, scene->r.cfra, 0);
+ }
+
for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (seq->flag & SELECT) {
seq->flag &= ~SEQ_ALLSEL;
}
@@ -635,11 +656,51 @@ static void sequencer_select_linked_handle(const bContext *C,
}
}
-/* Check if click happened on image which belongs to strip. If multiple strips are found, loop
- * through them in order. */
-static Sequence *seq_select_seq_from_preview(const bContext *C,
- const int mval[2],
- const bool center)
+/** Collect sequencer that are candidates for being selected. */
+struct SeqSelect_Link {
+ struct SeqSelect_Link *next, *prev;
+ Sequence *seq;
+ /** Only use for center selection. */
+ float center_dist_sq;
+};
+
+static int seq_sort_for_depth_select(const void *a, const void *b)
+{
+ const struct SeqSelect_Link *slink_a = a;
+ const struct SeqSelect_Link *slink_b = b;
+
+ /* Exactly overlapping strips, sort by machine (so the top-most is first). */
+ if (slink_a->seq->machine < slink_b->seq->machine) {
+ return 1;
+ }
+ if (slink_a->seq->machine > slink_b->seq->machine) {
+ return -1;
+ }
+ return 0;
+}
+
+static int seq_sort_for_center_select(const void *a, const void *b)
+{
+ const struct SeqSelect_Link *slink_a = a;
+ const struct SeqSelect_Link *slink_b = b;
+ if (slink_a->center_dist_sq > slink_b->center_dist_sq) {
+ return 1;
+ }
+ if (slink_a->center_dist_sq < slink_b->center_dist_sq) {
+ return -1;
+ }
+
+ /* Exactly overlapping strips, use depth. */
+ return seq_sort_for_depth_select(a, b);
+}
+
+/**
+ * Check if click happened on image which belongs to strip.
+ * If multiple strips are found, loop through them in order
+ * (depth (top-most first) or closest to mouse when `center` is true).
+ */
+static Sequence *seq_select_seq_from_preview(
+ const bContext *C, const int mval[2], const bool toggle, const bool extend, const bool center)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
@@ -650,70 +711,82 @@ static Sequence *seq_select_seq_from_preview(const bContext *C,
float mouseco_view[2];
UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseco_view[0], &mouseco_view[1]);
+ /* Always update the coordinates (check extended after). */
+ const bool use_cycle = (!WM_cursor_test_motion_and_update(mval) || extend || toggle);
+
SeqCollection *strips = SEQ_query_rendered_strips(seqbase, scene->r.cfra, sseq->chanshown);
/* Allow strips this far from the closest center to be included.
* This allows cycling over center points which are near enough
* to overlapping from the users perspective. */
- const float center_threshold_cycle_px = 5.0f;
- const float center_dist_sq_eps = square_f(center_threshold_cycle_px * U.pixelsize);
+ const float center_dist_sq_max = square_f(75.0f * U.pixelsize);
const float center_scale_px[2] = {
UI_view2d_scale_get_x(v2d),
UI_view2d_scale_get_y(v2d),
};
- float center_co_best[2] = {0.0f};
-
- if (center) {
- Sequence *seq_best = NULL;
- float center_dist_sq_best = 0.0f;
-
- Sequence *seq;
- SEQ_ITERATOR_FOREACH (seq, strips) {
- float co[2];
- SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, co);
- const float center_dist_sq_test = len_squared_v2v2(co, mouseco_view);
- if ((seq_best == NULL) || (center_dist_sq_test < center_dist_sq_best)) {
- seq_best = seq;
- center_dist_sq_best = center_dist_sq_test;
- copy_v2_v2(center_co_best, co);
- }
- }
- }
+ struct SeqSelect_Link *slink_active = NULL;
+ Sequence *seq_active = SEQ_select_active_get(scene);
ListBase strips_ordered = {NULL};
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, strips) {
bool isect = false;
+ float center_dist_sq_test = 0.0f;
if (center) {
/* Detect overlapping center points (scaled by the zoom level). */
float co[2];
SEQ_image_transform_origin_offset_pixelspace_get(scene, seq, co);
- sub_v2_v2(co, center_co_best);
+ sub_v2_v2(co, mouseco_view);
mul_v2_v2(co, center_scale_px);
- isect = len_squared_v2(co) <= center_dist_sq_eps;
+ center_dist_sq_test = len_squared_v2(co);
+ isect = center_dist_sq_test <= center_dist_sq_max;
+ if (isect) {
+ /* Use an active strip penalty for "center" selection when cycle is enabled. */
+ if (use_cycle && (seq == seq_active) && (seq_active->flag & SELECT)) {
+ center_dist_sq_test = square_f(sqrtf(center_dist_sq_test) + (3.0f * U.pixelsize));
+ }
+ }
}
else {
isect = seq_point_image_isect(scene, seq, mouseco_view);
}
if (isect) {
- BLI_remlink(seqbase, seq);
- BLI_addtail(&strips_ordered, seq);
+ struct SeqSelect_Link *slink = MEM_callocN(sizeof(*slink), __func__);
+ slink->seq = seq;
+ slink->center_dist_sq = center_dist_sq_test;
+ BLI_addtail(&strips_ordered, slink);
+
+ if (seq == seq_active) {
+ slink_active = slink;
+ }
}
}
SEQ_collection_free(strips);
- SEQ_sort(&strips_ordered);
- Sequence *seq_active = SEQ_select_active_get(scene);
- Sequence *seq_select = strips_ordered.first;
- LISTBASE_FOREACH (Sequence *, seq_iter, &strips_ordered) {
- if (seq_iter == seq_active && seq_iter->next != NULL) {
- seq_select = seq_iter->next;
- break;
+ BLI_listbase_sort(&strips_ordered,
+ center ? seq_sort_for_center_select : seq_sort_for_depth_select);
+
+ struct SeqSelect_Link *slink_select = strips_ordered.first;
+ Sequence *seq_select = NULL;
+ if (slink_select != NULL) {
+ /* Only use special behavior for the active strip when it's selected. */
+ if ((center == false) && slink_active && (seq_active->flag & SELECT)) {
+ if (use_cycle) {
+ if (slink_active->next) {
+ slink_select = slink_active->next;
+ }
+ }
+ else {
+ /* Match object selection behavior: keep the current active item unless cycle is enabled.
+ * Clicking again in the same location will cycle away from the active object. */
+ slink_select = slink_active;
+ }
}
+ seq_select = slink_select->seq;
}
- BLI_movelisttolist(seqbase, &strips_ordered);
+ BLI_freelistN(&strips_ordered);
return seq_select;
}
@@ -759,7 +832,7 @@ static void sequencer_select_strip_impl(const Editing *ed,
action = 0;
}
else {
- if ((seq->flag & SELECT) == 0 || is_active) {
+ if (!((seq->flag & SELECT) && is_active)) {
action = 1;
}
else if (toggle) {
@@ -812,7 +885,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
int handle_clicked = SEQ_SIDE_NONE;
Sequence *seq = NULL;
if (region->regiontype == RGN_TYPE_PREVIEW) {
- seq = seq_select_seq_from_preview(C, mval, center);
+ seq = seq_select_seq_from_preview(C, mval, toggle, extend, center);
}
else {
seq = find_nearest_seq(scene, v2d, &handle_clicked, mval);
@@ -821,7 +894,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
/* NOTE: `side_of_frame` and `linked_time` functionality is designed to be shared on one keymap,
* therefore both properties can be true at the same time. */
if (seq && RNA_boolean_get(op->ptr, "linked_time")) {
- if (!extend) {
+ if (!extend && !toggle) {
ED_sequencer_deselect_all(scene);
}
sequencer_select_strip_impl(ed, seq, handle_clicked, extend, deselect, toggle);
@@ -833,7 +906,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
/* Select left, right or overlapping the current frame. */
if (RNA_boolean_get(op->ptr, "side_of_frame")) {
- if (!extend) {
+ if (!extend && !toggle) {
ED_sequencer_deselect_all(scene);
}
sequencer_select_side_of_frame(C, v2d, mval, scene);
@@ -843,7 +916,7 @@ static int sequencer_select_exec(bContext *C, wmOperator *op)
/* On Alt selection, select the strip and bordering handles. */
if (seq && RNA_boolean_get(op->ptr, "linked_handle")) {
- if (!extend) {
+ if (!extend && !toggle) {
ED_sequencer_deselect_all(scene);
}
sequencer_select_linked_handle(C, seq, handle_clicked);
@@ -1694,11 +1767,17 @@ static const EnumPropertyItem sequencer_prop_select_grouped_types[] = {
#define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
-static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_type(ListBase *seqbasep,
+ const bool is_preview,
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbasep) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
seq->flag |= SELECT;
changed = true;
@@ -1708,12 +1787,18 @@ static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel
return changed;
}
-static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_type_basic(ListBase *seqbase,
+ const bool is_preview,
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
const bool is_sound = SEQ_IS_SOUND(actseq);
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
seq->flag |= SELECT;
changed = true;
@@ -1723,12 +1808,18 @@ static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int c
return changed;
}
-static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_type_effect(ListBase *seqbase,
+ const bool is_preview,
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
const bool is_effect = SEQ_IS_EFFECT(actseq);
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) &&
(is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
seq->flag |= SELECT;
@@ -1739,7 +1830,10 @@ static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int
return changed;
}
-static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_data(ListBase *seqbase,
+ const bool is_preview,
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
const char *dir = actseq->strip ? actseq->strip->dir : NULL;
@@ -1749,7 +1843,10 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
}
if (SEQ_HAS_PATH(actseq) && dir) {
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip &&
STREQ(seq->strip->dir, dir)) {
seq->flag |= SELECT;
@@ -1759,7 +1856,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
}
else if (actseq->type == SEQ_TYPE_SCENE) {
Scene *sce = actseq->scene;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
seq->flag |= SELECT;
changed = true;
@@ -1768,7 +1865,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
}
else if (actseq->type == SEQ_TYPE_MOVIECLIP) {
MovieClip *clip = actseq->clip;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP &&
seq->clip == clip) {
seq->flag |= SELECT;
@@ -1778,7 +1875,7 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
}
else if (actseq->type == SEQ_TYPE_MASK) {
struct Mask *mask = actseq->mask;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
seq->flag |= SELECT;
changed = true;
@@ -1789,7 +1886,10 @@ static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel
return changed;
}
-static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel)
+static bool select_grouped_effect(ListBase *seqbase,
+ const bool is_preview,
+ Sequence *actseq,
+ const int channel)
{
bool changed = false;
bool effects[SEQ_TYPE_MAX + 1];
@@ -1798,14 +1898,20 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int chann
effects[i] = false;
}
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
effects[seq->type] = true;
}
}
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
if (seq->seq1) {
seq->seq1->flag |= SELECT;
@@ -1823,11 +1929,14 @@ static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int chann
return changed;
}
-static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
+static bool select_grouped_time_overlap(ListBase *seqbase, const bool is_preview, Sequence *actseq)
{
bool changed = false;
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) {
seq->flag |= SELECT;
changed = true;
@@ -1856,12 +1965,11 @@ static void query_lower_channel_strips(Sequence *seq_reference,
/* Select all strips within time range and with lower channel of initial selection. Then select
* effect chains of these strips. */
-static bool select_grouped_effect_link(Editing *ed,
+static bool select_grouped_effect_link(ListBase *seqbase,
+ const bool is_preview,
Sequence *UNUSED(actseq),
const int UNUSED(channel))
{
- ListBase *seqbase = SEQ_active_seqbase_get(ed);
-
/* Get collection of strips. */
SeqCollection *collection = SEQ_query_selected_strips(seqbase);
const int selected_strip_count = BLI_gset_len(collection->set);
@@ -1874,6 +1982,9 @@ static bool select_grouped_effect_link(Editing *ed,
/* Actual logic. */
Sequence *seq;
SEQ_ITERATOR_FOREACH (seq, collection) {
+ if (is_preview && (seq->tmp_tag == false)) {
+ continue;
+ }
seq->flag |= SELECT;
}
@@ -1889,9 +2000,17 @@ static bool select_grouped_effect_link(Editing *ed,
static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
- Editing *ed = SEQ_editing_get(scene);
+ ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene));
Sequence *actseq = SEQ_select_active_get(scene);
+ const bool is_preview = sequencer_view_preview_poll(C);
+ if (is_preview) {
+ SEQ_query_rendered_strips_to_tag(seqbase, scene->r.cfra, 0);
+ if (actseq && actseq->tmp_tag == false) {
+ actseq = NULL;
+ }
+ }
+
if (actseq == NULL) {
BKE_report(op->reports, RPT_ERROR, "No active sequence!");
return OPERATOR_CANCELLED;
@@ -1904,7 +2023,7 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
bool changed = false;
if (!extend) {
- LISTBASE_FOREACH (Sequence *, seq, SEQ_active_seqbase_get(ed)) {
+ LISTBASE_FOREACH (Sequence *, seq, seqbase) {
seq->flag &= ~SELECT;
changed = true;
}
@@ -1912,25 +2031,25 @@ static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
switch (type) {
case SEQ_SELECT_GROUP_TYPE:
- changed |= select_grouped_type(ed, actseq, channel);
+ changed |= select_grouped_type(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_TYPE_BASIC:
- changed |= select_grouped_type_basic(ed, actseq, channel);
+ changed |= select_grouped_type_basic(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_TYPE_EFFECT:
- changed |= select_grouped_type_effect(ed, actseq, channel);
+ changed |= select_grouped_type_effect(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_DATA:
- changed |= select_grouped_data(ed, actseq, channel);
+ changed |= select_grouped_data(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT:
- changed |= select_grouped_effect(ed, actseq, channel);
+ changed |= select_grouped_effect(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_EFFECT_LINK:
- changed |= select_grouped_effect_link(ed, actseq, channel);
+ changed |= select_grouped_effect_link(seqbase, is_preview, actseq, channel);
break;
case SEQ_SELECT_GROUP_OVERLAP:
- changed |= select_grouped_time_overlap(ed, actseq);
+ changed |= select_grouped_time_overlap(seqbase, is_preview, actseq);
break;
default:
BLI_assert(0);