Blender  V2.93
sequencer_select.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19 
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "BLI_blenlib.h"
29 #include "BLI_ghash.h"
30 #include "BLI_math.h"
31 #include "BLI_utildefines.h"
32 
33 #include "DNA_scene_types.h"
34 
35 #include "BKE_context.h"
36 #include "BKE_report.h"
37 
38 #include "WM_api.h"
39 #include "WM_types.h"
40 
41 #include "RNA_define.h"
42 
43 #include "SEQ_iterator.h"
44 #include "SEQ_select.h"
45 #include "SEQ_sequencer.h"
46 #include "SEQ_transform.h"
47 
48 /* For menu, popup, icons, etc. */
49 
50 #include "ED_outliner.h"
51 #include "ED_screen.h"
52 #include "ED_select_utils.h"
53 #include "ED_sequencer.h"
54 
55 #include "UI_view2d.h"
56 
57 /* Own include. */
58 #include "sequencer_intern.h"
59 
60 /* -------------------------------------------------------------------- */
64 static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */
65 {
66  Sequence *neighbor;
67 
68  neighbor = find_neighboring_sequence(scene, test, SEQ_SIDE_LEFT, -1);
69  if (neighbor) {
70  /* Only select neighbor handle if matching handle from test seq is also selected,
71  * or if neighbor was not selected at all up till now.
72  * Otherwise, we get odd mismatch when shift-alt-rmb selecting neighbor strips... */
73  if (!(neighbor->flag & SELECT) || (test->flag & SEQ_LEFTSEL)) {
74  neighbor->flag |= SEQ_RIGHTSEL;
75  }
76  neighbor->flag |= SELECT;
77  recurs_sel_seq(neighbor);
78  }
79  neighbor = find_neighboring_sequence(scene, test, SEQ_SIDE_RIGHT, -1);
80  if (neighbor) {
81  if (!(neighbor->flag & SELECT) || (test->flag & SEQ_RIGHTSEL)) { /* See comment above. */
82  neighbor->flag |= SEQ_LEFTSEL;
83  }
84  neighbor->flag |= SELECT;
85  recurs_sel_seq(neighbor);
86  }
87 }
88 
89 /* Used for mouse selection in SEQUENCER_OT_select. */
90 static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
91 {
92  Sequence *seq;
93 
94  for (seq = seqbase->first; seq; seq = seq->next) {
95  if (channel == seq->machine) {
96  switch (sel_side) {
97  case SEQ_SIDE_LEFT:
98  if (frame > (seq->startdisp)) {
99  seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
100  seq->flag |= SELECT;
101  }
102  break;
103  case SEQ_SIDE_RIGHT:
104  if (frame < (seq->startdisp)) {
105  seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
106  seq->flag |= SELECT;
107  }
108  break;
109  case SEQ_SIDE_BOTH:
110  seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
111  seq->flag |= SELECT;
112  break;
113  }
114  }
115  }
116 }
117 
118 /* Used for mouse selection in SEQUENCER_OT_select_side. */
119 static void select_active_side_range(ListBase *seqbase,
120  const int sel_side,
121  const int frame_ranges[MAXSEQ],
122  const int frame_ignore)
123 {
124  Sequence *seq;
125 
126  for (seq = seqbase->first; seq; seq = seq->next) {
127  if (seq->machine < MAXSEQ) {
128  const int frame = frame_ranges[seq->machine];
129  if (frame == frame_ignore) {
130  continue;
131  }
132  switch (sel_side) {
133  case SEQ_SIDE_LEFT:
134  if (frame > (seq->startdisp)) {
135  seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
136  seq->flag |= SELECT;
137  }
138  break;
139  case SEQ_SIDE_RIGHT:
140  if (frame < (seq->startdisp)) {
141  seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
142  seq->flag |= SELECT;
143  }
144  break;
145  case SEQ_SIDE_BOTH:
146  seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
147  seq->flag |= SELECT;
148  break;
149  }
150  }
151  }
152 }
153 
154 /* Used for mouse selection in SEQUENCER_OT_select */
155 static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
156 {
157  Sequence *seq;
158 
159  for (seq = seqbase->first; seq; seq = seq->next) {
160  if (seq_link->machine != seq->machine) {
161  int left_match = (seq->startdisp == seq_link->startdisp) ? 1 : 0;
162  int right_match = (seq->enddisp == seq_link->enddisp) ? 1 : 0;
163 
164  if (left_match && right_match) {
165  /* Direct match, copy the selection settings. */
166  seq->flag &= ~(SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
167  seq->flag |= seq_link->flag & (SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
168 
169  recurs_sel_seq(seq);
170  }
171  else if (seq_link->flag & SELECT && (left_match || right_match)) {
172 
173  /* Clear for reselection. */
174  seq->flag &= ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
175 
176  if (left_match && seq_link->flag & SEQ_LEFTSEL) {
177  seq->flag |= SELECT | SEQ_LEFTSEL;
178  }
179 
180  if (right_match && seq_link->flag & SEQ_RIGHTSEL) {
181  seq->flag |= SELECT | SEQ_RIGHTSEL;
182  }
183 
184  recurs_sel_seq(seq);
185  }
186  }
187  }
188 }
189 
190 #if 0 /* BRING BACK */
191 void select_surround_from_last(Scene *scene)
192 {
193  Sequence *seq = get_last_seq(scene);
194 
195  if (seq == NULL) {
196  return;
197  }
198 
200 }
201 #endif
202 
204 {
205  Editing *ed = SEQ_editing_get(scene, false);
206 
207  if (deselect_all) {
209  }
210 
212 
213  if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
214  if (seq->strip) {
216  }
217  }
218  else if (seq->type == SEQ_TYPE_SOUND_RAM) {
219  if (seq->strip) {
221  }
222  }
223  seq->flag |= SELECT;
224  recurs_sel_seq(seq);
225 }
226 
227 void seq_rectf(Sequence *seq, rctf *rect)
228 {
229  rect->xmin = seq->startdisp;
230  rect->xmax = seq->enddisp;
231  rect->ymin = seq->machine + SEQ_STRIP_OFSBOTTOM;
232  rect->ymax = seq->machine + SEQ_STRIP_OFSTOP;
233 }
234 
236 {
237  /* sel: 0==unselected, 1==selected, -1==don't care. */
238  Sequence *seq;
239  Editing *ed = SEQ_editing_get(scene, false);
240 
241  if (ed == NULL) {
242  return NULL;
243  }
244 
245  if (sel > 0) {
246  sel = SELECT;
247  }
248 
249  for (seq = ed->seqbasep->first; seq; seq = seq->next) {
250  if ((seq != test) && (test->machine == seq->machine) &&
251  ((sel == -1) || (sel && (seq->flag & SELECT)) ||
252  (sel == 0 && (seq->flag & SELECT) == 0))) {
253  switch (lr) {
254  case SEQ_SIDE_LEFT:
255  if (test->startdisp == (seq->enddisp)) {
256  return seq;
257  }
258  break;
259  case SEQ_SIDE_RIGHT:
260  if (test->enddisp == (seq->startdisp)) {
261  return seq;
262  }
263  break;
264  }
265  }
266  }
267  return NULL;
268 }
269 
270 Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[2])
271 {
272  Sequence *seq;
273  Editing *ed = SEQ_editing_get(scene, false);
274  float x, y;
275  float pixelx;
276  float handsize;
277  float displen;
278  *hand = SEQ_SIDE_NONE;
279 
280  if (ed == NULL) {
281  return NULL;
282  }
283 
284  pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
285 
286  UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
287 
288  seq = ed->seqbasep->first;
289 
290  while (seq) {
291  if (seq->machine == (int)y) {
292  /* Check for both normal strips, and strips that have been flipped horizontally. */
293  if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) ||
294  ((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x))) {
296 
297  /* Clamp handles to defined size in pixel space. */
298  handsize = 2.0f * sequence_handle_size_get_clamped(seq, pixelx);
299  displen = (float)abs(seq->startdisp - seq->enddisp);
300 
301  /* Don't even try to grab the handles of small strips. */
302  if (displen / pixelx > 16) {
303 
304  /* Set the max value to handle to 1/3 of the total len when its
305  * less than 28. This is important because otherwise selecting
306  * handles happens even when you click in the middle. */
307  if ((displen / 3) < 30 * pixelx) {
308  handsize = displen / 3;
309  }
310  else {
311  CLAMP(handsize, 7 * pixelx, 30 * pixelx);
312  }
313 
314  if (handsize + seq->startdisp >= x) {
315  *hand = SEQ_SIDE_LEFT;
316  }
317  else if (-handsize + seq->enddisp <= x) {
318  *hand = SEQ_SIDE_RIGHT;
319  }
320  }
321  }
322  return seq;
323  }
324  }
325  seq = seq->next;
326  }
327  return NULL;
328 }
329 
330 #if 0
331 static void select_neighbor_from_last(Scene *scene, int lr)
332 {
334  Sequence *neighbor;
335  bool changed = false;
336  if (seq) {
337  neighbor = find_neighboring_sequence(scene, seq, lr, -1);
338  if (neighbor) {
339  switch (lr) {
340  case SEQ_SIDE_LEFT:
341  neighbor->flag |= SELECT;
342  recurs_sel_seq(neighbor);
343  neighbor->flag |= SEQ_RIGHTSEL;
344  seq->flag |= SEQ_LEFTSEL;
345  break;
346  case SEQ_SIDE_RIGHT:
347  neighbor->flag |= SELECT;
348  recurs_sel_seq(neighbor);
349  neighbor->flag |= SEQ_LEFTSEL;
350  seq->flag |= SEQ_RIGHTSEL;
351  break;
352  }
353  seq->flag |= SELECT;
354  changed = true;
355  }
356  }
357  if (changed) {
358  /* Pass. */
359  }
360 }
361 #endif
362 
363 void recurs_sel_seq(Sequence *seq_meta)
364 {
365  Sequence *seq;
366 
367  seq = seq_meta->seqbase.first;
368  while (seq) {
369 
370  if (seq_meta->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) {
371  seq->flag &= ~SEQ_ALLSEL;
372  }
373  else if (seq_meta->flag & SELECT) {
374  seq->flag |= SELECT;
375  }
376  else {
377  seq->flag &= ~SEQ_ALLSEL;
378  }
379 
380  if (seq->seqbase.first) {
381  recurs_sel_seq(seq);
382  }
383 
384  seq = seq->next;
385  }
386 }
387 
390 /* -------------------------------------------------------------------- */
395 {
396  int action = RNA_enum_get(op->ptr, "action");
397 
399  Editing *ed = SEQ_editing_get(scene, false);
400  Sequence *seq;
401 
402  if (action == SEL_TOGGLE) {
403  action = SEL_SELECT;
404  for (seq = ed->seqbasep->first; seq; seq = seq->next) {
405  if (seq->flag & SEQ_ALLSEL) {
406  action = SEL_DESELECT;
407  break;
408  }
409  }
410  }
411 
412  for (seq = ed->seqbasep->first; seq; seq = seq->next) {
413  switch (action) {
414  case SEL_SELECT:
415  seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
416  seq->flag |= SELECT;
417  break;
418  case SEL_DESELECT:
419  seq->flag &= ~SEQ_ALLSEL;
420  break;
421  case SEL_INVERT:
422  if (seq->flag & SEQ_ALLSEL) {
423  seq->flag &= ~SEQ_ALLSEL;
424  }
425  else {
426  seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
427  seq->flag |= SELECT;
428  }
429  break;
430  }
431  }
432 
434 
436 
437  return OPERATOR_FINISHED;
438 }
439 
441 {
442  /* Identifiers. */
443  ot->name = "(De)select All";
444  ot->idname = "SEQUENCER_OT_select_all";
445  ot->description = "Select or deselect all strips";
446 
447  /* Api callbacks. */
450 
451  /* Flags. */
452  ot->flag = OPTYPE_UNDO;
453 
455 }
456 
459 /* -------------------------------------------------------------------- */
464 {
466  Editing *ed = SEQ_editing_get(scene, false);
467  Sequence *seq;
468 
469  for (seq = ed->seqbasep->first; seq; seq = seq->next) {
470  if (seq->flag & SELECT) {
471  seq->flag &= ~SEQ_ALLSEL;
472  }
473  else {
474  seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
475  seq->flag |= SELECT;
476  }
477  }
478 
480 
482 
483  return OPERATOR_FINISHED;
484 }
485 
487 {
488  /* Identifiers. */
489  ot->name = "Select Inverse";
490  ot->idname = "SEQUENCER_OT_select_inverse";
491  ot->description = "Select unselected strips";
492 
493  /* Api callbacks. */
496 
497  /* Flags. */
498  ot->flag = OPTYPE_UNDO;
499 }
500 
503 /* -------------------------------------------------------------------- */
508 {
511  Editing *ed = SEQ_editing_get(scene, false);
512  const bool extend = RNA_boolean_get(op->ptr, "extend");
513  const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
514  const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle");
515  const bool linked_time = RNA_boolean_get(op->ptr, "linked_time");
516  bool side_of_frame = RNA_boolean_get(op->ptr, "side_of_frame");
517  bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
518  int mval[2];
519  int ret_value = OPERATOR_CANCELLED;
520 
521  mval[0] = RNA_int_get(op->ptr, "mouse_x");
522  mval[1] = RNA_int_get(op->ptr, "mouse_y");
523 
524  Sequence *seq, *neighbor, *act_orig;
525  int hand, sel_side;
526 
527  if (ed == NULL) {
528  return OPERATOR_CANCELLED;
529  }
530 
531  if (extend) {
532  wait_to_deselect_others = false;
533  }
534 
535  seq = find_nearest_seq(scene, v2d, &hand, mval);
536 
537  /* XXX - not nice, Ctrl+RMB needs to do side_of_frame only when not over a strip */
538  if (seq && linked_time) {
539  side_of_frame = false;
540  }
541 
542  /* Select left, right or overlapping the current frame. */
543  if (side_of_frame) {
544  /* Use different logic for this. */
545  if (extend == false) {
547  }
548 
549  const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
550 
552  if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) ||
553  ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) {
554  /* Select left or right. */
555  seq_iter->flag |= SELECT;
556  recurs_sel_seq(seq_iter);
557  }
558  }
559 
560  {
561  SpaceSeq *sseq = CTX_wm_space_seq(C);
562  if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
563  TimeMarker *tmarker;
564 
565  for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
566  if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
567  ((x >= CFRA) && (tmarker->frame >= CFRA))) {
568  tmarker->flag |= SELECT;
569  }
570  else {
571  tmarker->flag &= ~SELECT;
572  }
573  }
574  }
575  }
576 
577  ret_value = OPERATOR_FINISHED;
578  }
579  else {
580  act_orig = ed->act_seq;
581 
582  if (seq) {
583  /* Are we trying to select a handle that's already selected? */
584  const bool handle_selected = ((hand == SEQ_SIDE_LEFT) && (seq->flag & SEQ_LEFTSEL)) ||
585  ((hand == SEQ_SIDE_RIGHT) && (seq->flag & SEQ_RIGHTSEL));
586 
587  if (wait_to_deselect_others && (seq->flag & SELECT) &&
588  (hand == SEQ_SIDE_NONE || handle_selected)) {
589  ret_value = OPERATOR_RUNNING_MODAL;
590  }
591  else if (!extend && !linked_handle) {
593  ret_value = OPERATOR_FINISHED;
594  }
595  else {
596  ret_value = OPERATOR_FINISHED;
597  }
598 
600 
601  if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
602  if (seq->strip) {
604  }
605  }
606  else if (seq->type == SEQ_TYPE_SOUND_RAM) {
607  if (seq->strip) {
609  }
610  }
611 
612  /* On Alt selection, select the strip and bordering handles. */
613  if (linked_handle) {
614  if (!ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
615  /* First click selects the strip and its adjacent handles (if valid).
616  * Second click selects the strip,
617  * both of its handles and its adjacent handles (if valid). */
618  const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
619 
620  if (!extend) {
622  }
623  seq->flag &= ~SEQ_ALLSEL;
624  seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
626  }
627  else {
628  /* Always select the strip under the cursor. */
629  seq->flag |= SELECT;
630 
631  /* First click selects adjacent handles on that side.
632  * Second click selects all strips in that direction.
633  * If there are no adjacent strips, it just selects all in that direction.
634  */
635  sel_side = hand;
636  neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
637  if (neighbor) {
638  switch (sel_side) {
639  case SEQ_SIDE_LEFT:
640  if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
641  if (extend == 0) {
643  }
644  seq->flag |= SELECT;
645 
647  }
648  else {
649  if (extend == 0) {
651  }
652  seq->flag |= SELECT;
653 
654  neighbor->flag |= SELECT;
655  recurs_sel_seq(neighbor);
656  neighbor->flag |= SEQ_RIGHTSEL;
657  seq->flag |= SEQ_LEFTSEL;
658  }
659  break;
660  case SEQ_SIDE_RIGHT:
661  if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
662  if (extend == 0) {
664  }
665  seq->flag |= SELECT;
666 
668  }
669  else {
670  if (extend == 0) {
672  }
673  seq->flag |= SELECT;
674 
675  neighbor->flag |= SELECT;
676  recurs_sel_seq(neighbor);
677  neighbor->flag |= SEQ_LEFTSEL;
678  seq->flag |= SEQ_RIGHTSEL;
679  }
680  break;
681  }
682  }
683  else {
684  if (extend == 0) {
686  }
687  select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
688  }
689  }
690 
691  ret_value = OPERATOR_FINISHED;
692  }
693  else {
694  if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
695  switch (hand) {
696  case SEQ_SIDE_NONE:
697  if (linked_handle == 0) {
698  seq->flag &= ~SEQ_ALLSEL;
699  }
700  break;
701  case SEQ_SIDE_LEFT:
702  seq->flag ^= SEQ_LEFTSEL;
703  break;
704  case SEQ_SIDE_RIGHT:
705  seq->flag ^= SEQ_RIGHTSEL;
706  break;
707  }
708  ret_value = OPERATOR_FINISHED;
709  }
710  else {
711  seq->flag |= SELECT;
712  if (hand == SEQ_SIDE_LEFT) {
713  seq->flag |= SEQ_LEFTSEL;
714  }
715  if (hand == SEQ_SIDE_RIGHT) {
716  seq->flag |= SEQ_RIGHTSEL;
717  }
718  }
719  }
720 
721  recurs_sel_seq(seq);
722 
723  if (linked_time) {
724  select_linked_time(ed->seqbasep, seq);
725  }
726 
727  BLI_assert((ret_value & OPERATOR_CANCELLED) == 0);
728  }
729  else if (deselect_all) {
731  ret_value = OPERATOR_FINISHED;
732  }
733  }
734 
736 
738 
739  return ret_value;
740 }
741 
743 {
744  PropertyRNA *prop;
745 
746  /* Identifiers. */
747  ot->name = "Select";
748  ot->idname = "SEQUENCER_OT_select";
749  ot->description = "Select a strip (last selected becomes the \"active strip\")";
750 
751  /* Api callbacks. */
756 
757  /* Flags. */
758  ot->flag = OPTYPE_UNDO;
759 
760  /* Properties. */
762 
763  prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
765 
766  prop = RNA_def_boolean(ot->srna,
767  "deselect_all",
768  false,
769  "Deselect On Nothing",
770  "Deselect all when nothing under the cursor");
772 
773  prop = RNA_def_boolean(ot->srna,
774  "linked_handle",
775  false,
776  "Linked Handle",
777  "Select handles next to the active strip");
779 
780  prop = RNA_def_boolean(
781  ot->srna, "linked_time", false, "Linked Time", "Select other strips at the same time");
783 
784  prop = RNA_def_boolean(
785  ot->srna,
786  "side_of_frame",
787  false,
788  "Side of Frame",
789  "Select all strips on same side of the current frame as the mouse cursor");
791 }
792 
795 /* -------------------------------------------------------------------- */
799 /* Run recursively to select linked. */
801 {
802  Editing *ed = SEQ_editing_get(scene, false);
803 
804  if (ed == NULL) {
805  return false;
806  }
807 
808  bool changed = false;
809 
811  if ((seq->flag & SELECT) == 0) {
812  continue;
813  }
814  /* Only get unselected neighbors. */
816  if (neighbor) {
817  neighbor->flag |= SELECT;
818  recurs_sel_seq(neighbor);
819  changed = true;
820  }
821  neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, 0);
822  if (neighbor) {
823  neighbor->flag |= SELECT;
824  recurs_sel_seq(neighbor);
825  changed = true;
826  }
827  }
828 
829  return changed;
830 }
831 
832 /* Select only one linked strip on each side. */
833 static bool select_more_less_seq__internal(Scene *scene, bool select_more)
834 {
835  Editing *ed = SEQ_editing_get(scene, false);
836 
837  if (ed == NULL) {
838  return false;
839  }
840 
841  GSet *neighbors = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "Linked strips");
842  const int neighbor_selection_filter = select_more ? 0 : SELECT;
843  const int selection_filter = select_more ? SELECT : 0;
844 
846  if ((seq->flag & SELECT) != selection_filter) {
847  continue;
848  }
850  scene, seq, SEQ_SIDE_LEFT, neighbor_selection_filter);
851  if (neighbor) {
852  BLI_gset_add(neighbors, neighbor);
853  }
854  neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, neighbor_selection_filter);
855  if (neighbor) {
856  BLI_gset_add(neighbors, neighbor);
857  }
858  }
859 
860  bool changed = false;
861  GSetIterator gsi;
862  BLI_gsetIterator_init(&gsi, neighbors);
863  while (!BLI_gsetIterator_done(&gsi)) {
864  Sequence *neighbor = BLI_gsetIterator_getKey(&gsi);
865  if (select_more) {
866  neighbor->flag |= SELECT;
867  recurs_sel_seq(neighbor);
868  }
869  else {
870  neighbor->flag &= ~SELECT;
871  }
872  changed = true;
873  BLI_gsetIterator_step(&gsi);
874  }
875 
876  BLI_gset_free(neighbors, NULL);
877  return changed;
878 }
879 
881 {
883 
885  return OPERATOR_CANCELLED;
886  }
887 
889 
891 
892  return OPERATOR_FINISHED;
893 }
894 
896 {
897  /* Identifiers. */
898  ot->name = "Select More";
899  ot->idname = "SEQUENCER_OT_select_more";
900  ot->description = "Select more strips adjacent to the current selection";
901 
902  /* Api callbacks. */
905 
906  /* Flags. */
908 }
909 
912 /* -------------------------------------------------------------------- */
917 {
919 
920  if (!select_more_less_seq__internal(scene, false)) {
921  return OPERATOR_CANCELLED;
922  }
923 
925 
927 
928  return OPERATOR_FINISHED;
929 }
930 
932 {
933  /* Identifiers. */
934  ot->name = "Select Less";
935  ot->idname = "SEQUENCER_OT_select_less";
936  ot->description = "Shrink the current selection of adjacent selected strips";
937 
938  /* Api callbacks. */
941 
942  /* Flags. */
944 }
945 
948 /* -------------------------------------------------------------------- */
953 {
956 
957  bool extend = RNA_boolean_get(op->ptr, "extend");
958 
959  Sequence *mouse_seq;
960  int selected, hand;
961 
962  /* This works like UV, not mesh. */
963  mouse_seq = find_nearest_seq(scene, v2d, &hand, event->mval);
964  if (!mouse_seq) {
965  return OPERATOR_FINISHED; /* User error as with mesh?? */
966  }
967 
968  if (extend == 0) {
970  }
971 
972  mouse_seq->flag |= SELECT;
973  recurs_sel_seq(mouse_seq);
974 
975  selected = 1;
976  while (selected) {
977  selected = select_linked_internal(scene);
978  }
979 
981 
983 
984  return OPERATOR_FINISHED;
985 }
986 
988 {
989  /* Identifiers. */
990  ot->name = "Select Pick Linked";
991  ot->idname = "SEQUENCER_OT_select_linked_pick";
992  ot->description = "Select a chain of linked strips nearest to the mouse pointer";
993 
994  /* Api callbacks. */
997 
998  /* Flags. */
1000 
1001  /* Properties. */
1002  RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1003 }
1004 
1007 /* -------------------------------------------------------------------- */
1012 {
1014  bool selected;
1015 
1016  selected = true;
1017  while (selected) {
1018  selected = select_linked_internal(scene);
1019  }
1020 
1022 
1024 
1025  return OPERATOR_FINISHED;
1026 }
1027 
1029 {
1030  /* Identifiers. */
1031  ot->name = "Select Linked";
1032  ot->idname = "SEQUENCER_OT_select_linked";
1033  ot->description = "Select all strips adjacent to the current selection";
1034 
1035  /* Api callbacks. */
1038 
1039  /* Flags. */
1041 }
1042 
1045 /* -------------------------------------------------------------------- */
1049 enum {
1056 };
1057 
1059  {SEQ_SELECT_HANDLES_SIDE_LEFT, "LEFT", 0, "Left", ""},
1060  {SEQ_SELECT_HANDLES_SIDE_RIGHT, "RIGHT", 0, "Right", ""},
1061  {SEQ_SELECT_HANDLES_SIDE_BOTH, "BOTH", 0, "Both", ""},
1062  {SEQ_SELECT_HANDLES_SIDE_LEFT_NEIGHBOR, "LEFT_NEIGHBOR", 0, "Left Neighbor", ""},
1063  {SEQ_SELECT_HANDLES_SIDE_RIGHT_NEIGHBOR, "RIGHT_NEIGHBOR", 0, "Right Neighbor", ""},
1064  {SEQ_SELECT_HANDLES_SIDE_BOTH_NEIGHBORS, "BOTH_NEIGHBORS", 0, "Both Neighbors", ""},
1065  {0, NULL, 0, NULL, NULL},
1066 };
1067 
1069 {
1071  Editing *ed = SEQ_editing_get(scene, false);
1072  Sequence *seq;
1073  int sel_side = RNA_enum_get(op->ptr, "side");
1074 
1075  for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1076  if (seq->flag & SELECT) {
1077  Sequence *l_neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, -1);
1078  Sequence *r_neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, -1);
1079 
1080  switch (sel_side) {
1082  seq->flag &= ~SEQ_RIGHTSEL;
1083  seq->flag |= SEQ_LEFTSEL;
1084  break;
1086  seq->flag &= ~SEQ_LEFTSEL;
1087  seq->flag |= SEQ_RIGHTSEL;
1088  break;
1090  seq->flag |= SEQ_LEFTSEL | SEQ_RIGHTSEL;
1091  break;
1093  if (l_neighbor) {
1094  if (!(l_neighbor->flag & SELECT)) {
1095  l_neighbor->flag |= SEQ_RIGHTSEL;
1096  }
1097  }
1098  break;
1100  if (r_neighbor) {
1101  if (!(r_neighbor->flag & SELECT)) {
1102  r_neighbor->flag |= SEQ_LEFTSEL;
1103  }
1104  }
1105  break;
1107  if (l_neighbor) {
1108  if (!(l_neighbor->flag & SELECT)) {
1109  l_neighbor->flag |= SEQ_RIGHTSEL;
1110  }
1111  }
1112  if (r_neighbor) {
1113  if (!(r_neighbor->flag & SELECT)) {
1114  r_neighbor->flag |= SEQ_LEFTSEL;
1115  }
1116  break;
1117  }
1118  }
1119  }
1120  }
1121  /* Select strips */
1122  for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1123  if ((seq->flag & SEQ_LEFTSEL) || (seq->flag & SEQ_RIGHTSEL)) {
1124  if (!(seq->flag & SELECT)) {
1125  seq->flag |= SELECT;
1126  recurs_sel_seq(seq);
1127  }
1128  }
1129  }
1130 
1132 
1134 
1135  return OPERATOR_FINISHED;
1136 }
1137 
1139 {
1140  /* Identifiers. */
1141  ot->name = "Select Handles";
1142  ot->idname = "SEQUENCER_OT_select_handles";
1143  ot->description = "Select gizmo handles on the sides of the selected strip";
1144 
1145  /* Api callbacks. */
1148 
1149  /* Flags. */
1151 
1152  /* Properties. */
1153  RNA_def_enum(ot->srna,
1154  "side",
1157  "Side",
1158  "The side of the handle that is selected");
1159 }
1160 
1163 /* -------------------------------------------------------------------- */
1168 {
1170  Editing *ed = SEQ_editing_get(scene, false);
1171  const bool extend = RNA_boolean_get(op->ptr, "extend");
1172  const int side = RNA_enum_get(op->ptr, "side");
1173 
1174  if (ed == NULL) {
1175  return OPERATOR_CANCELLED;
1176  }
1177  if (extend == false) {
1179  }
1180  const int timeline_frame = CFRA;
1182  bool test = false;
1183  switch (side) {
1184  case -1:
1185  test = (timeline_frame >= seq->enddisp);
1186  break;
1187  case 1:
1188  test = (timeline_frame <= seq->startdisp);
1189  break;
1190  case 0:
1191  test = (timeline_frame <= seq->enddisp) && (timeline_frame >= seq->startdisp);
1192  break;
1193  }
1194 
1195  if (test) {
1196  seq->flag |= SELECT;
1197  recurs_sel_seq(seq);
1198  }
1199  }
1200 
1202 
1204 
1205  return OPERATOR_FINISHED;
1206 }
1207 
1209 {
1210  static const EnumPropertyItem sequencer_select_left_right_types[] = {
1211  {-1, "LEFT", 0, "Left", "Select to the left of the current frame"},
1212  {1, "RIGHT", 0, "Right", "Select to the right of the current frame"},
1213  {0, NULL, 0, NULL, NULL},
1214  };
1215 
1216  /* Identifiers. */
1217  ot->name = "Select Side of Frame";
1218  ot->idname = "SEQUENCER_OT_select_side_of_frame";
1219  ot->description = "Select strips relative to the current frame";
1220 
1221  /* Api callbacks. */
1224 
1225  /* Flags. */
1226  ot->flag = OPTYPE_UNDO;
1227 
1228  /* Properties. */
1229  RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1230  ot->prop = RNA_def_enum(ot->srna, "side", sequencer_select_left_right_types, 0, "Side", "");
1231 }
1232 
1235 /* -------------------------------------------------------------------- */
1240 {
1242  Editing *ed = SEQ_editing_get(scene, false);
1243 
1244  const int sel_side = RNA_enum_get(op->ptr, "side");
1245  const int frame_init = sel_side == SEQ_SIDE_LEFT ? INT_MIN : INT_MAX;
1246  int frame_ranges[MAXSEQ];
1247  bool selected = false;
1248 
1249  copy_vn_i(frame_ranges, ARRAY_SIZE(frame_ranges), frame_init);
1250 
1251  LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
1252  if (UNLIKELY(seq->machine >= MAXSEQ)) {
1253  continue;
1254  }
1255  int *frame_limit_p = &frame_ranges[seq->machine];
1256  if (seq->flag & SELECT) {
1257  selected = true;
1258  if (sel_side == SEQ_SIDE_LEFT) {
1259  *frame_limit_p = max_ii(*frame_limit_p, seq->startdisp);
1260  }
1261  else {
1262  *frame_limit_p = min_ii(*frame_limit_p, seq->startdisp);
1263  }
1264  }
1265  }
1266 
1267  if (selected == false) {
1268  return OPERATOR_CANCELLED;
1269  }
1270 
1271  select_active_side_range(ed->seqbasep, sel_side, frame_ranges, frame_init);
1272 
1274 
1276 
1277  return OPERATOR_FINISHED;
1278 }
1279 
1281 {
1282  /* Identifiers. */
1283  ot->name = "Select Side";
1284  ot->idname = "SEQUENCER_OT_select_side";
1285  ot->description = "Select strips on the nominated side of the selected strips";
1286 
1287  /* Api callbacks. */
1290 
1291  /* Flags. */
1293 
1294  /* Properties. */
1295  RNA_def_enum(ot->srna,
1296  "side",
1298  SEQ_SIDE_BOTH,
1299  "Side",
1300  "The side to which the selection is applied");
1301 }
1302 
1305 /* -------------------------------------------------------------------- */
1310 {
1312  View2D *v2d = UI_view2d_fromcontext(C);
1313  Editing *ed = SEQ_editing_get(scene, false);
1314 
1315  if (ed == NULL) {
1316  return OPERATOR_CANCELLED;
1317  }
1318 
1319  const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
1320  const bool handles = RNA_boolean_get(op->ptr, "include_handles");
1321  const bool select = (sel_op != SEL_OP_SUB);
1322 
1323  if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1325  }
1326 
1327  rctf rectf;
1329  UI_view2d_region_to_view_rctf(v2d, &rectf, &rectf);
1330 
1331  LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
1332  rctf rq;
1333  seq_rectf(seq, &rq);
1334  if (BLI_rctf_isect(&rq, &rectf, NULL)) {
1335  if (handles) {
1336  /* Get the handles draw size. */
1337  float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
1338  float handsize = sequence_handle_size_get_clamped(seq, pixelx);
1339 
1340  /* Right handle. */
1341  if (rectf.xmax > (seq->enddisp - handsize)) {
1342  if (select) {
1343  seq->flag |= SELECT | SEQ_RIGHTSEL;
1344  }
1345  else {
1346  /* Deselect the strip if it's left with no handles selected. */
1347  if ((seq->flag & SEQ_RIGHTSEL) && ((seq->flag & SEQ_LEFTSEL) == 0)) {
1348  seq->flag &= ~SELECT;
1349  }
1350  seq->flag &= ~SEQ_RIGHTSEL;
1351  }
1352  }
1353  /* Left handle. */
1354  if (rectf.xmin < (seq->startdisp + handsize)) {
1355  if (select) {
1356  seq->flag |= SELECT | SEQ_LEFTSEL;
1357  }
1358  else {
1359  /* Deselect the strip if it's left with no handles selected. */
1360  if ((seq->flag & SEQ_LEFTSEL) && ((seq->flag & SEQ_RIGHTSEL) == 0)) {
1361  seq->flag &= ~SELECT;
1362  }
1363  seq->flag &= ~SEQ_LEFTSEL;
1364  }
1365  }
1366  }
1367 
1368  /* Regular box selection. */
1369  else {
1371  seq->flag &= ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
1372  }
1373  }
1374  }
1375 
1377 
1379 
1380  return OPERATOR_FINISHED;
1381 }
1382 
1384 {
1386  View2D *v2d = &CTX_wm_region(C)->v2d;
1387 
1388  const bool tweak = RNA_boolean_get(op->ptr, "tweak");
1389 
1390  if (tweak) {
1391  int hand_dummy;
1392  Sequence *seq = find_nearest_seq(scene, v2d, &hand_dummy, event->mval);
1393  if (seq != NULL) {
1395  }
1396  }
1397 
1398  return WM_gesture_box_invoke(C, op, event);
1399 }
1400 
1402 {
1403  PropertyRNA *prop;
1404 
1405  /* Identifiers. */
1406  ot->name = "Box Select";
1407  ot->idname = "SEQUENCER_OT_select_box";
1408  ot->description = "Select strips using box selection";
1409 
1410  /* Api callbacks. */
1415 
1417 
1418  /* Flags. */
1419  ot->flag = OPTYPE_UNDO;
1420 
1421  /* Properties. */
1424 
1425  prop = RNA_def_boolean(
1426  ot->srna, "tweak", 0, "Tweak", "Operator has been activated using a tweak event");
1428  prop = RNA_def_boolean(
1429  ot->srna, "include_handles", 0, "Select Handles", "Select the strips and their handles");
1431 }
1432 
1435 /* -------------------------------------------------------------------- */
1439 enum {
1447 };
1448 
1450  {SEQ_SELECT_GROUP_TYPE, "TYPE", 0, "Type", "Shared strip type"},
1452  "TYPE_BASIC",
1453  0,
1454  "Global Type",
1455  "All strips of same basic type (graphical or sound)"},
1457  "TYPE_EFFECT",
1458  0,
1459  "Effect Type",
1460  "Shared strip effect type (if active strip is not an effect one, select all non-effect "
1461  "strips)"},
1462  {SEQ_SELECT_GROUP_DATA, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
1463  {SEQ_SELECT_GROUP_EFFECT, "EFFECT", 0, "Effect", "Shared effects"},
1465  "EFFECT_LINK",
1466  0,
1467  "Effect/Linked",
1468  "Other strips affected by the active one (sharing some time, and below or effect-assigned)"},
1469  {SEQ_SELECT_GROUP_OVERLAP, "OVERLAP", 0, "Overlap", "Overlapping time"},
1470  {0, NULL, 0, NULL, NULL},
1471 };
1472 
1473 #define SEQ_IS_SOUND(_seq) ((_seq->type & SEQ_TYPE_SOUND_RAM) && !(_seq->type & SEQ_TYPE_EFFECT))
1474 
1475 #define SEQ_IS_EFFECT(_seq) ((_seq->type & SEQ_TYPE_EFFECT) != 0)
1476 
1477 #define SEQ_USE_DATA(_seq) \
1478  (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq))
1479 
1480 #define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
1481 
1482 static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel)
1483 {
1484  bool changed = false;
1485 
1487  if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
1488  seq->flag |= SELECT;
1489  changed = true;
1490  }
1491  }
1492 
1493  return changed;
1494 }
1495 
1496 static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel)
1497 {
1498  bool changed = false;
1499  const bool is_sound = SEQ_IS_SOUND(actseq);
1500 
1502  if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
1503  seq->flag |= SELECT;
1504  changed = true;
1505  }
1506  }
1507 
1508  return changed;
1509 }
1510 
1511 static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel)
1512 {
1513  bool changed = false;
1514  const bool is_effect = SEQ_IS_EFFECT(actseq);
1515 
1517  if (SEQ_CHANNEL_CHECK(seq, channel) &&
1518  (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
1519  seq->flag |= SELECT;
1520  changed = true;
1521  }
1522  }
1523 
1524  return changed;
1525 }
1526 
1527 static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel)
1528 {
1529  bool changed = false;
1530  const char *dir = actseq->strip ? actseq->strip->dir : NULL;
1531 
1532  if (!SEQ_USE_DATA(actseq)) {
1533  return changed;
1534  }
1535 
1536  if (SEQ_HAS_PATH(actseq) && dir) {
1538  if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip &&
1539  STREQ(seq->strip->dir, dir)) {
1540  seq->flag |= SELECT;
1541  changed = true;
1542  }
1543  }
1544  }
1545  else if (actseq->type == SEQ_TYPE_SCENE) {
1546  Scene *sce = actseq->scene;
1548  if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
1549  seq->flag |= SELECT;
1550  changed = true;
1551  }
1552  }
1553  }
1554  else if (actseq->type == SEQ_TYPE_MOVIECLIP) {
1555  MovieClip *clip = actseq->clip;
1557  if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP &&
1558  seq->clip == clip) {
1559  seq->flag |= SELECT;
1560  changed = true;
1561  }
1562  }
1563  }
1564  else if (actseq->type == SEQ_TYPE_MASK) {
1565  struct Mask *mask = actseq->mask;
1567  if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
1568  seq->flag |= SELECT;
1569  changed = true;
1570  }
1571  }
1572  }
1573 
1574  return changed;
1575 }
1576 
1577 static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel)
1578 {
1579  bool changed = false;
1580  bool effects[SEQ_TYPE_MAX + 1];
1581 
1582  for (int i = 0; i <= SEQ_TYPE_MAX; i++) {
1583  effects[i] = false;
1584  }
1585 
1587  if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
1588  ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
1589  effects[seq->type] = true;
1590  }
1591  }
1592 
1594  if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
1595  if (seq->seq1) {
1596  seq->seq1->flag |= SELECT;
1597  }
1598  if (seq->seq2) {
1599  seq->seq2->flag |= SELECT;
1600  }
1601  if (seq->seq3) {
1602  seq->seq3->flag |= SELECT;
1603  }
1604  changed = true;
1605  }
1606  }
1607 
1608  return changed;
1609 }
1610 
1612 {
1613  bool changed = false;
1614 
1616  if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) {
1617  seq->flag |= SELECT;
1618  changed = true;
1619  }
1620  }
1621 
1622  return changed;
1623 }
1624 
1625 static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel)
1626 {
1627  bool changed = false;
1628  const bool is_audio = ((actseq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(actseq));
1629  int startdisp = actseq->startdisp;
1630  int enddisp = actseq->enddisp;
1631  int machine = actseq->machine;
1632  SeqIterator iter;
1633 
1635  seq->tmp = NULL;
1636  }
1637 
1638  actseq->tmp = POINTER_FROM_INT(true);
1639 
1640  Sequence *seq = NULL;
1641  for (SEQ_iterator_begin(ed, &iter, true); iter.valid; SEQ_iterator_next(&iter)) {
1642  seq = iter.seq;
1643 
1644  /* Ignore all seqs already selected. */
1645  /* Ignore all seqs not sharing some time with active one. */
1646  /* Ignore all seqs of incompatible types (audio vs video). */
1647  if (!SEQ_CHANNEL_CHECK(seq, channel) || (seq->flag & SELECT) || (seq->startdisp >= enddisp) ||
1648  (seq->enddisp < startdisp) || (!is_audio && SEQ_IS_SOUND(seq)) ||
1649  (is_audio && !((seq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(seq)))) {
1650  continue;
1651  }
1652 
1653  /* If the seq is an effect one, we need extra checking. */
1654  if (SEQ_IS_EFFECT(seq) && ((seq->seq1 && seq->seq1->tmp) || (seq->seq2 && seq->seq2->tmp) ||
1655  (seq->seq3 && seq->seq3->tmp))) {
1656  if (startdisp > seq->startdisp) {
1657  startdisp = seq->startdisp;
1658  }
1659  if (enddisp < seq->enddisp) {
1660  enddisp = seq->enddisp;
1661  }
1662  if (machine < seq->machine) {
1663  machine = seq->machine;
1664  }
1665 
1666  seq->tmp = POINTER_FROM_INT(true);
1667 
1668  seq->flag |= SELECT;
1669  changed = true;
1670 
1671  /* Unfortunately, we must restart checks from the beginning. */
1672  SEQ_iterator_end(&iter);
1673  SEQ_iterator_begin(ed, &iter, true);
1674  }
1675 
1676  /* Video strips below active one, or any strip for audio (order doesn't matter here). */
1677  else if (seq->machine < machine || is_audio) {
1678  seq->flag |= SELECT;
1679  changed = true;
1680  }
1681  }
1682  SEQ_iterator_end(&iter);
1683 
1684  return changed;
1685 }
1686 
1687 #undef SEQ_IS_SOUND
1688 #undef SEQ_IS_EFFECT
1689 #undef SEQ_USE_DATA
1690 
1692 {
1694  Editing *ed = SEQ_editing_get(scene, false);
1696 
1697  if (actseq == NULL) {
1698  BKE_report(op->reports, RPT_ERROR, "No active sequence!");
1699  return OPERATOR_CANCELLED;
1700  }
1701 
1702  const int type = RNA_enum_get(op->ptr, "type");
1703  const int channel = RNA_boolean_get(op->ptr, "use_active_channel") ? actseq->machine : 0;
1704  const bool extend = RNA_boolean_get(op->ptr, "extend");
1705 
1706  bool changed = false;
1707 
1708  if (!extend) {
1710  seq->flag &= ~SELECT;
1711  changed = true;
1712  }
1713  }
1714 
1715  switch (type) {
1716  case SEQ_SELECT_GROUP_TYPE:
1717  changed |= select_grouped_type(ed, actseq, channel);
1718  break;
1720  changed |= select_grouped_type_basic(ed, actseq, channel);
1721  break;
1723  changed |= select_grouped_type_effect(ed, actseq, channel);
1724  break;
1725  case SEQ_SELECT_GROUP_DATA:
1726  changed |= select_grouped_data(ed, actseq, channel);
1727  break;
1729  changed |= select_grouped_effect(ed, actseq, channel);
1730  break;
1732  changed |= select_grouped_effect_link(ed, actseq, channel);
1733  break;
1735  changed |= select_grouped_time_overlap(ed, actseq);
1736  break;
1737  default:
1738  BLI_assert(0);
1739  break;
1740  }
1741 
1742  if (changed) {
1745  return OPERATOR_FINISHED;
1746  }
1747 
1748  return OPERATOR_CANCELLED;
1749 }
1750 
1752 {
1753  /* Identifiers. */
1754  ot->name = "Select Grouped";
1755  ot->idname = "SEQUENCER_OT_select_grouped";
1756  ot->description = "Select all strips grouped by various properties";
1757 
1758  /* Api callbacks. */
1762 
1763  /* Flags. */
1765 
1766  /* Properties. */
1767  ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", "");
1769  "extend",
1770  false,
1771  "Extend",
1772  "Extend selection instead of deselecting everything first");
1774  "use_active_channel",
1775  false,
1776  "Same Channel",
1777  "Only consider strips on the same channel as the active one");
1778 }
1779 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct SpaceSeq * CTX_wm_space_seq(const bContext *C)
Definition: context.c:827
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
#define BLI_assert(a)
Definition: BLI_assert.h:58
struct GSet GSet
Definition: BLI_ghash.h:189
unsigned int BLI_ghashutil_ptrhash(const void *key)
GSet * BLI_gset_new(GSetHashFP hashfp, GSetCmpFP cmpfp, const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:1125
bool BLI_ghashutil_ptrcmp(const void *a, const void *b)
BLI_INLINE bool BLI_gsetIterator_done(GSetIterator *gsi)
Definition: BLI_ghash.h:263
BLI_INLINE void BLI_gsetIterator_init(GSetIterator *gsi, GSet *gs)
Definition: BLI_ghash.h:247
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
Definition: BLI_ghash.c:1253
BLI_INLINE void BLI_gsetIterator_step(GSetIterator *gsi)
Definition: BLI_ghash.h:259
BLI_INLINE void * BLI_gsetIterator_getKey(GSetIterator *gsi)
Definition: BLI_ghash.h:255
bool BLI_gset_add(GSet *gs, void *key)
Definition: BLI_ghash.c:1160
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:172
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
void copy_vn_i(int *array_tar, const int size, const int val)
Definition: math_vector.c:1374
#define FILE_MAXDIR
bool BLI_rctf_isect(const struct rctf *src1, const struct rctf *src2, struct rctf *dest)
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition: BLI_rect.h:153
BLI_INLINE float BLI_rctf_size_x(const struct rctf *rct)
Definition: BLI_rect.h:161
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, const size_t maxncpy) ATTR_NONNULL()
Definition: string.c:108
#define ARRAY_SIZE(arr)
#define POINTER_FROM_INT(i)
#define UNUSED(x)
#define SET_FLAG_FROM_TEST(value, test, flag)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define CFRA
@ SEQ_RIGHTSEL
@ SEQ_LEFTSEL
#define SEQ_HAS_PATH(_seq)
#define SEQ_ALLSEL
#define SEQ_STRIP_OFSBOTTOM
#define MAXSEQ
@ SEQ_TYPE_SOUND_RAM
@ SEQ_TYPE_MAX
@ SEQ_TYPE_META
@ SEQ_TYPE_SCENE
@ SEQ_TYPE_MOVIECLIP
@ SEQ_TYPE_IMAGE
@ SEQ_TYPE_EFFECT
@ SEQ_TYPE_MOVIE
@ SEQ_TYPE_MASK
#define SEQ_STRIP_OFSTOP
@ SEQ_MARKER_TRANS
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_outliner_select_sync_from_sequence_tag(struct bContext *C)
Definition: outliner_sync.c:74
bool ED_operator_sequencer_active(struct bContext *C)
Definition: screen_ops.c:319
#define SEL_OP_USE_PRE_DESELECT(sel_op)
@ SEL_SELECT
@ SEL_INVERT
@ SEL_DESELECT
@ SEL_TOGGLE
eSelectOp
@ SEL_OP_SUB
void ED_sequencer_deselect_all(struct Scene *scene)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
Group RGB to Bright Vector Camera CLAMP
@ PROP_SKIP_SAVE
Definition: RNA_types.h:204
#define C
Definition: RandGen.cpp:39
@ SEQ_SIDE_RIGHT
Definition: SEQ_sequencer.h:42
@ SEQ_SIDE_BOTH
Definition: SEQ_sequencer.h:43
@ SEQ_SIDE_LEFT
Definition: SEQ_sequencer.h:41
@ SEQ_SIDE_NONE
Definition: SEQ_sequencer.h:40
struct View2D * UI_view2d_fromcontext(const struct bContext *C)
void UI_view2d_region_to_view_rctf(const struct View2D *v2d, const struct rctf *rect_src, struct rctf *rect_dst) ATTR_NONNULL()
void UI_view2d_region_to_view(const struct View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
float UI_view2d_region_to_view_x(const struct View2D *v2d, float x)
Definition: view2d.c:1659
#define ND_SEQUENCER
Definition: WM_types.h:337
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
#define NC_SCENE
Definition: WM_types.h:279
#define NA_SELECTED
Definition: WM_types.h:467
#define SELECT
Scene scene
void SEQ_iterator_end(SeqIterator *iter)
Definition: iterator.c:133
void SEQ_iterator_begin(Editing *ed, SeqIterator *iter, const bool use_current_sequences)
Definition: iterator.c:111
void SEQ_iterator_next(SeqIterator *iter)
Definition: iterator.c:123
int RNA_int_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6308
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
int RNA_enum_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6402
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
Definition: rna_define.c:1512
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, int default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3771
ListBase * SEQ_active_seqbase_get(const Editing *ed)
Definition: sequencer.c:350
Editing * SEQ_editing_get(Scene *scene, bool alloc)
Definition: sequencer.c:232
float sequence_handle_size_get_clamped(Sequence *seq, const float pixelx)
EnumPropertyItem prop_side_types[]
bool sequencer_edit_poll(bContext *C)
static void select_active_side_range(ListBase *seqbase, const int sel_side, const int frame_ranges[MAXSEQ], const int frame_ignore)
static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int sequencer_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
#define SEQ_USE_DATA(_seq)
static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel)
static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel)
void recurs_sel_seq(Sequence *seq_meta)
static int sequencer_box_select_exec(bContext *C, wmOperator *op)
static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel)
void SEQUENCER_OT_select_side_of_frame(wmOperatorType *ot)
@ SEQ_SELECT_HANDLES_SIDE_LEFT_NEIGHBOR
@ SEQ_SELECT_HANDLES_SIDE_LEFT
@ SEQ_SELECT_HANDLES_SIDE_BOTH
@ SEQ_SELECT_HANDLES_SIDE_BOTH_NEIGHBORS
@ SEQ_SELECT_HANDLES_SIDE_RIGHT_NEIGHBOR
@ SEQ_SELECT_HANDLES_SIDE_RIGHT
void SEQUENCER_OT_select_more(wmOperatorType *ot)
@ SEQ_SELECT_GROUP_TYPE_EFFECT
@ SEQ_SELECT_GROUP_TYPE_BASIC
@ SEQ_SELECT_GROUP_EFFECT_LINK
@ SEQ_SELECT_GROUP_EFFECT
@ SEQ_SELECT_GROUP_OVERLAP
@ SEQ_SELECT_GROUP_TYPE
@ SEQ_SELECT_GROUP_DATA
static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
#define SEQ_CHANNEL_CHECK(_seq, _chan)
static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
static void select_surrounding_handles(Scene *scene, Sequence *test)
void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool deselect_all)
static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot)
void seq_rectf(Sequence *seq, rctf *rect)
void SEQUENCER_OT_select_box(wmOperatorType *ot)
static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel)
static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
#define SEQ_IS_EFFECT(_seq)
static const EnumPropertyItem sequencer_prop_select_grouped_types[]
void SEQUENCER_OT_select_linked(wmOperatorType *ot)
void SEQUENCER_OT_select_side(wmOperatorType *ot)
static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
Sequence * find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[2])
static bool select_linked_internal(Scene *scene)
void SEQUENCER_OT_select(wmOperatorType *ot)
static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
void SEQUENCER_OT_select_grouped(wmOperatorType *ot)
void SEQUENCER_OT_select_handles(wmOperatorType *ot)
void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
Sequence * find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int sel)
static const EnumPropertyItem prop_select_handles_side_types[]
static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
void SEQUENCER_OT_select_less(wmOperatorType *ot)
static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel)
static int sequencer_select_side_exec(bContext *C, wmOperator *op)
static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op)
static int sequencer_select_exec(bContext *C, wmOperator *op)
static bool select_more_less_seq__internal(Scene *scene, bool select_more)
#define SEQ_IS_SOUND(_seq)
static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel)
Sequence * SEQ_select_active_get(Scene *scene)
Definition: strip_select.c:35
void SEQ_select_active_set(Scene *scene, Sequence *seq)
Definition: strip_select.c:46
bool SEQ_transform_sequence_can_be_translated(Sequence *seq)
ListBase * seqbasep
Sequence * act_seq
char act_sounddir[1024]
char act_imagedir[1024]
void * first
Definition: DNA_listBase.h:47
ListBase markers
struct Sequence * seq
Definition: SEQ_iterator.h:37
struct MovieClip * clip
struct Scene * scene
struct Sequence * seq3
struct Mask * mask
ListBase seqbase
struct Sequence * seq1
struct Sequence * seq2
struct Sequence * next
char dir[768]
unsigned int flag
struct TimeMarker * next
float xmax
Definition: DNA_vec_types.h:85
float xmin
Definition: DNA_vec_types.h:85
float ymax
Definition: DNA_vec_types.h:86
float ymin
Definition: DNA_vec_types.h:86
int mval[2]
Definition: WM_types.h:583
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
int(* modal)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:768
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
void(* cancel)(struct bContext *, struct wmOperator *)
Definition: WM_types.h:760
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
int(* exec)(struct bContext *, struct wmOperator *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:736
PropertyRNA * prop
Definition: WM_types.h:814
struct ReportList * reports
struct PointerRNA * ptr
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
__forceinline const avxi abs(const avxi &a)
Definition: util_avxi.h:186
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
ParamHandle ** handles
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition: wm_files.c:3156
void WM_gesture_box_cancel(bContext *C, wmOperator *op)
int WM_gesture_box_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int WM_gesture_box_modal(bContext *C, wmOperator *op, const wmEvent *event)
void WM_operator_properties_gesture_box(wmOperatorType *ot)
void WM_operator_properties_select_operation_simple(wmOperatorType *ot)
void WM_operator_properties_generic_select(wmOperatorType *ot)
void WM_operator_properties_select_all(wmOperatorType *ot)
void WM_operator_properties_border_to_rctf(struct wmOperator *op, rctf *rect)
int WM_generic_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
Definition: wm_operators.c:905
int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
Definition: wm_operators.c:982
int WM_generic_select_modal(bContext *C, wmOperator *op, const wmEvent *event)
Definition: wm_operators.c:838