Cleanup: VSE select operator

Operator combines more features and it wasn't very transparent which
properties are used in which feature and how they are used.

Features linked_time, side_of_frame and linked_handle are
isolated, logic moved into own function.

deselect_all property was removed as it practically equals to
!extend in all cases.

Functional change: Dragging existing selection will not change active
strip. Previously this could happen if click happened on strip that
wasn't active.

Reviewed By: campbellbarton

Differential Revision: https://developer.blender.org/D12320
This commit is contained in:
Richard Antalik 2021-09-08 00:01:00 +02:00
parent 4abbf6d82b
commit e6a1d488ab
Notes: blender-bot 2023-02-14 05:28:01 +01:00
Referenced by commit 7beb4a0e0a, Fix non-exiting property in keymap
2 changed files with 212 additions and 213 deletions

View File

@ -2606,8 +2606,7 @@ def km_sequencer(params):
for i in range(10)
)
),
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS'},
{"properties": [("deselect_all", True)]}),
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS'}, None),
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS', "shift": True},
{"properties": [("extend", True)]}),
("sequencer.select", {"type": params.select_mouse, "value": 'PRESS', "alt": True},

View File

@ -504,238 +504,245 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
/** \name Select Operator
* \{ */
static void sequencer_select_set_active(Scene *scene, Sequence *seq)
{
Editing *ed = SEQ_editing_get(scene);
SEQ_select_active_set(scene, seq);
if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
if (seq->strip) {
BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
}
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
if (seq->strip) {
BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
}
}
recurs_sel_seq(seq);
}
static void sequencer_select_do_updates(bContext *C, Scene *scene)
{
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
}
static void sequencer_select_side_of_frame(const bContext *C,
const View2D *v2d,
const int mval[2],
Scene *scene)
{
Editing *ed = SEQ_editing_get(scene);
const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) ||
((x >= CFRA) && (seq_iter->startdisp >= CFRA))) {
/* Select left or right. */
seq_iter->flag |= SELECT;
recurs_sel_seq(seq_iter);
}
}
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
TimeMarker *tmarker;
for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
((x >= CFRA) && (tmarker->frame >= CFRA))) {
tmarker->flag |= SELECT;
}
else {
tmarker->flag &= ~SELECT;
}
}
}
}
}
static void sequencer_select_linked_handle(const bContext *C,
Sequence *seq,
const int handle_clicked)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
if (!ELEM(handle_clicked, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
/* First click selects the strip and its adjacent handles (if valid).
* Second click selects the strip,
* both of its handles and its adjacent handles (if valid). */
const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
seq->flag &= ~SEQ_ALLSEL;
seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
select_surrounding_handles(scene, seq);
}
else {
/* Always select the strip under the cursor. */
seq->flag |= SELECT;
/* First click selects adjacent handles on that side.
* Second click selects all strips in that direction.
* If there are no adjacent strips, it just selects all in that direction.
*/
int sel_side = handle_clicked;
Sequence *neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
if (neighbor) {
switch (sel_side) {
case SEQ_SIDE_LEFT:
if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
seq->flag |= SELECT;
select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
}
else {
seq->flag |= SELECT;
neighbor->flag |= SELECT;
recurs_sel_seq(neighbor);
neighbor->flag |= SEQ_RIGHTSEL;
seq->flag |= SEQ_LEFTSEL;
}
break;
case SEQ_SIDE_RIGHT:
if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
seq->flag |= SELECT;
select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
}
else {
seq->flag |= SELECT;
neighbor->flag |= SELECT;
recurs_sel_seq(neighbor);
neighbor->flag |= SEQ_LEFTSEL;
seq->flag |= SEQ_RIGHTSEL;
}
break;
}
}
else {
select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
}
}
}
static bool element_already_selected(const Sequence *seq, const int handle_clicked)
{
const bool handle_already_selected = ((handle_clicked == SEQ_SIDE_LEFT) &&
(seq->flag & SEQ_LEFTSEL)) ||
((handle_clicked == SEQ_SIDE_RIGHT) &&
(seq->flag & SEQ_RIGHTSEL));
return ((seq->flag & SELECT) && handle_clicked == SEQ_SIDE_NONE) || handle_already_selected;
}
static void sequencer_select_strip_impl(const Editing *ed,
Sequence *seq,
const int handle_clicked,
const bool extend)
{
/* Deselect strip. */
if (extend && (seq->flag & SELECT) && ed->act_seq == seq) {
switch (handle_clicked) {
case SEQ_SIDE_NONE:
seq->flag &= ~SEQ_ALLSEL;
break;
case SEQ_SIDE_LEFT:
seq->flag ^= SEQ_LEFTSEL;
break;
case SEQ_SIDE_RIGHT:
seq->flag ^= SEQ_RIGHTSEL;
break;
}
}
else { /* Select strip. */
seq->flag |= SELECT;
if (handle_clicked == SEQ_SIDE_LEFT) {
seq->flag |= SEQ_LEFTSEL;
}
if (handle_clicked == SEQ_SIDE_RIGHT) {
seq->flag |= SEQ_RIGHTSEL;
}
}
}
static int sequencer_select_exec(bContext *C, wmOperator *op)
{
View2D *v2d = UI_view2d_fromcontext(C);
Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
const bool extend = RNA_boolean_get(op->ptr, "extend");
const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle");
const bool linked_time = RNA_boolean_get(op->ptr, "linked_time");
bool side_of_frame = RNA_boolean_get(op->ptr, "side_of_frame");
bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
int mval[2];
int ret_value = OPERATOR_CANCELLED;
mval[0] = RNA_int_get(op->ptr, "mouse_x");
mval[1] = RNA_int_get(op->ptr, "mouse_y");
Sequence *seq, *neighbor, *act_orig;
int hand, sel_side;
if (ed == NULL) {
return OPERATOR_CANCELLED;
}
if (extend) {
wait_to_deselect_others = false;
}
int mval[2];
mval[0] = RNA_int_get(op->ptr, "mouse_x");
mval[1] = RNA_int_get(op->ptr, "mouse_y");
seq = find_nearest_seq(scene, v2d, &hand, mval);
int handle_clicked;
Sequence *seq = find_nearest_seq(scene, v2d, &handle_clicked, mval);
/* XXX: not nice, Ctrl+RMB needs to do side_of_frame only when not over a strip. */
if (seq && linked_time) {
side_of_frame = false;
/* 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) {
ED_sequencer_deselect_all(scene);
}
sequencer_select_strip_impl(ed, seq, handle_clicked, extend);
select_linked_time(ed->seqbasep, seq);
sequencer_select_do_updates(C, scene);
sequencer_select_set_active(scene, seq);
return OPERATOR_FINISHED;
}
/* Select left, right or overlapping the current frame. */
if (side_of_frame) {
/* Use different logic for this. */
if (extend == false) {
if (RNA_boolean_get(op->ptr, "side_of_frame")) {
if (!extend) {
ED_sequencer_deselect_all(scene);
}
sequencer_select_side_of_frame(C, v2d, mval, scene);
sequencer_select_do_updates(C, scene);
return OPERATOR_FINISHED;
}
const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) ||
((x >= CFRA) && (seq_iter->startdisp >= CFRA))) {
/* Select left or right. */
seq_iter->flag |= SELECT;
recurs_sel_seq(seq_iter);
}
/* On Alt selection, select the strip and bordering handles. */
if (seq && RNA_boolean_get(op->ptr, "linked_handle")) {
if (!extend) {
ED_sequencer_deselect_all(scene);
}
sequencer_select_linked_handle(C, seq, handle_clicked);
sequencer_select_do_updates(C, scene);
sequencer_select_set_active(scene, seq);
return OPERATOR_FINISHED;
}
{
SpaceSeq *sseq = CTX_wm_space_seq(C);
if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
TimeMarker *tmarker;
const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
((x >= CFRA) && (tmarker->frame >= CFRA))) {
tmarker->flag |= SELECT;
}
else {
tmarker->flag &= ~SELECT;
}
}
}
}
/* Clicking on already selected element falls on modal operation.
* All strips are deselected on mouse button release unless extend mode is used. */
if (seq && element_already_selected(seq, handle_clicked) && wait_to_deselect_others && !extend) {
return OPERATOR_RUNNING_MODAL;
}
int ret_value = OPERATOR_CANCELLED;
if (!extend) {
ED_sequencer_deselect_all(scene);
ret_value = OPERATOR_FINISHED;
}
else {
act_orig = ed->act_seq;
if (seq) {
/* Are we trying to select a handle that's already selected? */
const bool handle_selected = ((hand == SEQ_SIDE_LEFT) && (seq->flag & SEQ_LEFTSEL)) ||
((hand == SEQ_SIDE_RIGHT) && (seq->flag & SEQ_RIGHTSEL));
if (wait_to_deselect_others && (seq->flag & SELECT) &&
(hand == SEQ_SIDE_NONE || handle_selected)) {
ret_value = OPERATOR_RUNNING_MODAL;
}
else if (!extend && !linked_handle) {
ED_sequencer_deselect_all(scene);
ret_value = OPERATOR_FINISHED;
}
else {
ret_value = OPERATOR_FINISHED;
}
SEQ_select_active_set(scene, seq);
if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
if (seq->strip) {
BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
}
}
else if (seq->type == SEQ_TYPE_SOUND_RAM) {
if (seq->strip) {
BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
}
}
/* On Alt selection, select the strip and bordering handles. */
if (linked_handle) {
if (!ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
/* First click selects the strip and its adjacent handles (if valid).
* Second click selects the strip,
* both of its handles and its adjacent handles (if valid). */
const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
if (!extend) {
ED_sequencer_deselect_all(scene);
}
seq->flag &= ~SEQ_ALLSEL;
seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
select_surrounding_handles(scene, seq);
}
else {
/* Always select the strip under the cursor. */
seq->flag |= SELECT;
/* First click selects adjacent handles on that side.
* Second click selects all strips in that direction.
* If there are no adjacent strips, it just selects all in that direction.
*/
sel_side = hand;
neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
if (neighbor) {
switch (sel_side) {
case SEQ_SIDE_LEFT:
if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
if (extend == 0) {
ED_sequencer_deselect_all(scene);
}
seq->flag |= SELECT;
select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
}
else {
if (extend == 0) {
ED_sequencer_deselect_all(scene);
}
seq->flag |= SELECT;
neighbor->flag |= SELECT;
recurs_sel_seq(neighbor);
neighbor->flag |= SEQ_RIGHTSEL;
seq->flag |= SEQ_LEFTSEL;
}
break;
case SEQ_SIDE_RIGHT:
if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
if (extend == 0) {
ED_sequencer_deselect_all(scene);
}
seq->flag |= SELECT;
select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
}
else {
if (extend == 0) {
ED_sequencer_deselect_all(scene);
}
seq->flag |= SELECT;
neighbor->flag |= SELECT;
recurs_sel_seq(neighbor);
neighbor->flag |= SEQ_LEFTSEL;
seq->flag |= SEQ_RIGHTSEL;
}
break;
}
}
else {
if (extend == 0) {
ED_sequencer_deselect_all(scene);
}
select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
}
}
ret_value = OPERATOR_FINISHED;
}
else {
if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
switch (hand) {
case SEQ_SIDE_NONE:
if (linked_handle == 0) {
seq->flag &= ~SEQ_ALLSEL;
}
break;
case SEQ_SIDE_LEFT:
seq->flag ^= SEQ_LEFTSEL;
break;
case SEQ_SIDE_RIGHT:
seq->flag ^= SEQ_RIGHTSEL;
break;
}
ret_value = OPERATOR_FINISHED;
}
else {
seq->flag |= SELECT;
if (hand == SEQ_SIDE_LEFT) {
seq->flag |= SEQ_LEFTSEL;
}
if (hand == SEQ_SIDE_RIGHT) {
seq->flag |= SEQ_RIGHTSEL;
}
}
}
recurs_sel_seq(seq);
if (linked_time) {
select_linked_time(ed->seqbasep, seq);
}
BLI_assert((ret_value & OPERATOR_CANCELLED) == 0);
}
else if (deselect_all) {
ED_sequencer_deselect_all(scene);
ret_value = OPERATOR_FINISHED;
}
/* Nothing to select, but strips could be deselected. */
if (!seq) {
sequencer_select_do_updates(C, scene);
return ret_value;
}
ED_outliner_select_sync_from_sequence_tag(C);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
/* Do actual selection. */
sequencer_select_strip_impl(ed, seq, handle_clicked, extend);
ret_value = OPERATOR_FINISHED;
sequencer_select_do_updates(C, scene);
sequencer_select_set_active(scene, seq);
return ret_value;
}
@ -763,13 +770,6 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"deselect_all",
false,
"Deselect On Nothing",
"Deselect all when nothing under the cursor");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
"linked_handle",
false,