Blender V4.5
sequencer_edit.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BLI_string_ref.hh"
10#include "BLI_string_utils.hh"
11#include "BLI_vector.hh"
12#include "MEM_guardedalloc.h"
13
14#include "BLI_fileops.h"
15#include "BLI_listbase.h"
16#include "BLI_math_vector.h"
17#include "BLI_path_utils.hh"
18#include "BLI_string.h"
19#include "BLI_timecode.h"
20#include "BLI_utildefines.h"
21
22#include "BLT_translation.hh"
23
24#include "DNA_anim_types.h"
25#include "DNA_scene_types.h"
26#include "DNA_sound_types.h"
27
28#include "BKE_context.hh"
29#include "BKE_global.hh"
30#include "BKE_library.hh"
31#include "BKE_main.hh"
32#include "BKE_report.hh"
33#include "BKE_sound.h"
34
35#include "SEQ_add.hh"
36#include "SEQ_animation.hh"
37#include "SEQ_channels.hh"
38#include "SEQ_connect.hh"
39#include "SEQ_edit.hh"
40#include "SEQ_effects.hh"
41#include "SEQ_iterator.hh"
42#include "SEQ_prefetch.hh"
43#include "SEQ_relations.hh"
44#include "SEQ_render.hh"
45#include "SEQ_select.hh"
46#include "SEQ_sequencer.hh"
48#include "SEQ_time.hh"
49#include "SEQ_transform.hh"
50#include "SEQ_utils.hh"
51
52#include "ANIM_action_legacy.hh"
53
54#include "WM_api.hh"
55#include "WM_types.hh"
56
57#include "RNA_define.hh"
58#include "RNA_enum_types.hh"
59#include "RNA_prototypes.hh"
60
61/* For menu, popup, icons, etc. */
62#include "ED_fileselect.hh"
63#include "ED_numinput.hh"
64#include "ED_scene.hh"
65#include "ED_screen.hh"
66#include "ED_sequencer.hh"
67
68#include "UI_interface.hh"
69#include "UI_resources.hh"
70#include "UI_view2d.hh"
71
72#include "DEG_depsgraph.hh"
74
75/* Own include. */
76#include "sequencer_intern.hh"
77#include <cstddef>
78
79namespace blender::ed::vse {
80
81/* -------------------------------------------------------------------- */
84
86{
87 return maskedit_poll(C);
88}
89
91{
92 if (sseq && sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
93 return (seq::active_mask_get(scene) != nullptr);
94 }
95
96 return false;
97}
98
100{
101 SpaceSeq *sseq = CTX_wm_space_seq(C);
102
103 if (sseq) {
104 Scene *scene = CTX_data_scene(C);
105 return check_show_maskedit(sseq, scene);
106 }
107
108 return false;
109}
110
111bool check_show_imbuf(const SpaceSeq &sseq)
112{
113 return (sseq.mainb == SEQ_DRAW_IMG_IMBUF) &&
115}
116
117bool check_show_strip(const SpaceSeq &sseq)
118{
120}
121
123{
124 if (!BLI_str_startswith(fcurve->rna_path, "sequence_editor.strips_all[\"")) {
125 return false;
126 }
127
128 if (!BLI_str_endswith(fcurve->rna_path, "\"].color")) {
129 return false;
130 }
131
132 return true;
133}
134
136{
137 if (!scene->adt) {
138 return false;
139 }
140 if (!scene->adt->action) {
141 return false;
142 }
143
146 return true;
147 }
148 }
149
150 return false;
151}
152
154
155/* -------------------------------------------------------------------- */
158
160{
161 return (seq::editing_get(CTX_data_scene(C)) != nullptr);
162}
163
165{
166 if (!sequencer_edit_poll(C)) {
167 return false;
168 }
169 ARegion *region = CTX_wm_region(C);
170 if (!(region && (region->regiontype == RGN_TYPE_CHANNELS))) {
171 return false;
172 }
173 return true;
174}
175
180
181#if 0 /* UNUSED */
182bool sequencer_strip_poll(bContext *C)
183{
184 Editing *ed;
185 return (((ed = seq::editing_get(CTX_data_scene(C))) != nullptr) && (ed->act_strip != nullptr));
186}
187#endif
188
190{
191 Scene *scene = CTX_data_scene(C);
192 if (!ID_IS_EDITABLE(&scene->id)) {
193 return false;
194 }
195 Editing *ed = seq::editing_get(scene);
196 return (ed && (ed->act_strip != nullptr));
197}
198
200{
201 Editing *ed;
202 Strip *strip;
203 return (((ed = seq::editing_get(CTX_data_scene(C))) != nullptr) &&
204 ((strip = ed->act_strip) != nullptr) && STRIP_HAS_PATH(strip));
205}
206
208{
209 SpaceSeq *sseq = CTX_wm_space_seq(C);
210 if (sseq == nullptr) {
211 return false;
212 }
213 if (seq::editing_get(CTX_data_scene(C)) == nullptr) {
214 return false;
215 }
217 (sseq->mainb == SEQ_DRAW_IMG_IMBUF)))
218 {
219 return false;
220 }
221 ARegion *region = CTX_wm_region(C);
222 if (!(region && region->regiontype == RGN_TYPE_PREVIEW)) {
223 return false;
224 }
225
226 return true;
227}
228
230{
231 SpaceSeq *sseq = CTX_wm_space_seq(C);
232 if (sseq == nullptr) {
233 return false;
234 }
235 if (seq::editing_get(CTX_data_scene(C)) == nullptr) {
236 return false;
237 }
238 if (!(ELEM(sseq->view, SEQ_VIEW_PREVIEW) && (sseq->mainb == SEQ_DRAW_IMG_IMBUF))) {
239 return false;
240 }
241 ARegion *region = CTX_wm_region(C);
242 if (!(region && region->regiontype == RGN_TYPE_PREVIEW)) {
243 return false;
244 }
245
246 return true;
247}
248
250{
251 SpaceSeq *sseq = CTX_wm_space_seq(C);
252 if (sseq == nullptr) {
253 return false;
254 }
255 if (!check_show_strip(*sseq)) {
256 return false;
257 }
258 ARegion *region = CTX_wm_region(C);
259 if (!(region && region->regiontype == RGN_TYPE_WINDOW)) {
260 return false;
261 }
262 return true;
263}
264
266{
267 Scene *scene = CTX_data_scene(C);
268 Editing *ed = seq::editing_get(scene);
269
270 if (ed) {
271 Strip *active_strip = seq::select_active_get(scene);
272 if (active_strip && (active_strip->type & STRIP_TYPE_EFFECT)) {
273 return true;
274 }
275 }
276
277 return false;
278}
279
281{
282 Scene *scene = CTX_data_scene(C);
283 Strip *active_strip = seq::select_active_get(scene);
284
285 if (sequencer_effect_poll(C) && seq::effect_get_num_inputs(active_strip->type) == 2) {
286 return true;
287 }
288
289 return false;
290}
291
293
294/* -------------------------------------------------------------------- */
297
299{
300 Scene *scene = CTX_data_scene(C);
301 const bool do_all = RNA_boolean_get(op->ptr, "all");
302 const Editing *ed = seq::editing_get(scene);
303
304 seq::edit_remove_gaps(scene, ed->seqbasep, scene->r.cfra, do_all);
305
308
309 return OPERATOR_FINISHED;
310}
311
313{
314 /* Identifiers. */
315 ot->name = "Remove Gaps";
316 ot->idname = "SEQUENCER_OT_gap_remove";
317 ot->description =
318 "Remove gap at current frame to first strip at the right, independent of selection or "
319 "locked state of strips";
320
321 /* API callbacks. */
322 // ot->invoke = sequencer_snap_invoke;
324 ot->poll = sequencer_edit_poll;
325
326 /* Flags. */
328
329 RNA_def_boolean(ot->srna, "all", false, "All Gaps", "Do all gaps to right of current frame");
330}
331
333
334/* -------------------------------------------------------------------- */
337
339{
340 Scene *scene = CTX_data_scene(C);
341 const int frames = RNA_int_get(op->ptr, "frames");
342 const Editing *ed = seq::editing_get(scene);
343 seq::transform_offset_after_frame(scene, ed->seqbasep, frames, scene->r.cfra);
344
346
347 return OPERATOR_FINISHED;
348}
349
351{
352 /* Identifiers. */
353 ot->name = "Insert Gaps";
354 ot->idname = "SEQUENCER_OT_gap_insert";
355 ot->description =
356 "Insert gap at current frame to first strips at the right, independent of selection or "
357 "locked state of strips";
358
359 /* API callbacks. */
360 // ot->invoke = sequencer_snap_invoke;
362 ot->poll = sequencer_edit_poll;
363
364 /* Flags. */
366
367 RNA_def_int(ot->srna,
368 "frames",
369 10,
370 0,
371 INT_MAX,
372 "Frames",
373 "Frames to insert after current strip",
374 0,
375 1000);
376}
377
379
380/* -------------------------------------------------------------------- */
383
385{
386 Scene *scene = CTX_data_scene(C);
387
388 Editing *ed = seq::editing_get(scene);
390 int snap_frame;
391
392 snap_frame = RNA_int_get(op->ptr, "frame");
393
394 /* Check meta-strips. */
395 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
396 if (strip->flag & SELECT && !seq::transform_is_locked(channels, strip) &&
398 {
399 if ((strip->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) == 0) {
401 scene, strip, (snap_frame - strip->startofs) - strip->start);
402 }
403 else {
404 if (strip->flag & SEQ_LEFTSEL) {
405 seq::time_left_handle_frame_set(scene, strip, snap_frame);
406 }
407 else { /* SEQ_RIGHTSEL */
408 seq::time_right_handle_frame_set(scene, strip, snap_frame);
409 }
410 }
411
413 }
414 }
415
416 /* Test for effects and overlap. */
417 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
418 if (strip->flag & SELECT && !seq::transform_is_locked(channels, strip)) {
419 strip->flag &= ~SEQ_OVERLAP;
420 if (seq::transform_test_overlap(scene, ed->seqbasep, strip)) {
421 seq::transform_seqbase_shuffle(ed->seqbasep, strip, scene);
422 }
423 }
424 }
425
426 /* Recalculate bounds of effect strips, offsetting the keyframes if not snapping any handle. */
427 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
428 if (strip->type & STRIP_TYPE_EFFECT) {
429 const bool either_handle_selected = (strip->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) != 0;
430
431 if (strip->input1 && (strip->input1->flag & SELECT)) {
432 if (!either_handle_selected) {
434 scene, strip, (snap_frame - seq::time_left_handle_frame_get(scene, strip)));
435 }
436 }
437 else if (strip->input2 && (strip->input2->flag & SELECT)) {
438 if (!either_handle_selected) {
440 scene, strip, (snap_frame - seq::time_left_handle_frame_get(scene, strip)));
441 }
442 }
443 }
444 }
445
448
449 return OPERATOR_FINISHED;
450}
451
453 wmOperator *op,
454 const wmEvent * /*event*/)
455{
456 Scene *scene = CTX_data_scene(C);
457
458 int snap_frame;
459
460 snap_frame = scene->r.cfra;
461
462 RNA_int_set(op->ptr, "frame", snap_frame);
463 return sequencer_snap_exec(C, op);
464}
465
467{
468 /* Identifiers. */
469 ot->name = "Snap Strips to the Current Frame";
470 ot->idname = "SEQUENCER_OT_snap";
471 ot->description = "Frame where selected strips will be snapped";
472
473 /* API callbacks. */
474 ot->invoke = sequencer_snap_invoke;
475 ot->exec = sequencer_snap_exec;
476 ot->poll = sequencer_edit_poll;
477
478 /* Flags. */
480
481 RNA_def_int(ot->srna,
482 "frame",
483 0,
484 INT_MIN,
485 INT_MAX,
486 "Frame",
487 "Frame where selected strips will be snapped",
488 INT_MIN,
489 INT_MAX);
490}
491
493
494/* -------------------------------------------------------------------- */
497
498/* Modal Keymap */
499enum {
505};
506
528
530{
531 static const EnumPropertyItem modal_items[] = {
532 {SLIP_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
533 {SLIP_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
534
535 {SLIP_MODAL_PRECISION_ENABLE, "PRECISION_ENABLE", 0, "Precision Enable", ""},
536 {SLIP_MODAL_PRECISION_DISABLE, "PRECISION_DISABLE", 0, "Precision Disable", ""},
537 {SLIP_MODAL_CLAMP_TOGGLE, "CLAMP_TOGGLE", 0, "Clamp Toggle", ""},
538
539 {0, nullptr, 0, nullptr, nullptr},
540 };
541
542 wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Slip Modal");
543
544 /* This function is called for each space-type, only needs to add map once. */
545 if (keymap && keymap->modal_items) {
546 return;
547 }
548
549 keymap = WM_modalkeymap_ensure(keyconf, "Slip Modal", modal_items);
550
551 /* Assign map to operators. */
552 WM_modalkeymap_assign(keymap, "SEQUENCER_OT_slip");
553}
554
555static void slip_draw_status(bContext *C, const wmOperator *op)
556{
557 SlipData *data = static_cast<SlipData *>(op->customdata);
558
559 WorkspaceStatus status(C);
560
561 status.opmodal(IFACE_("Confirm"), op->type, SLIP_MODAL_CONFIRM);
562 status.opmodal(IFACE_("Cancel"), op->type, SLIP_MODAL_CANCEL);
563
564 status.opmodal(IFACE_("Precision"), op->type, SLIP_MODAL_PRECISION_ENABLE, data->precision);
565
566 if (data->can_clamp) {
567 status.opmodal(IFACE_("Clamp"), op->type, SLIP_MODAL_CLAMP_TOGGLE, data->clamp);
568 }
569 if (data->clamp_warning) {
570 status.item(TIP_("Not enough content to clamp strip(s)"), ICON_ERROR);
571 }
572}
573
574static void slip_update_header(const Scene *scene,
575 ScrArea *area,
576 SlipData *data,
577 const float offset)
578{
579 if (area == nullptr) {
580 return;
581 }
582
583 char msg[UI_MAX_DRAW_STR];
584 if (hasNumInput(&data->num_input)) {
585 char num_str[NUM_STR_REP_LEN];
586 outputNumInput(&data->num_input, num_str, scene->unit);
587 SNPRINTF(msg, IFACE_("Slip Offset: Frames: %s"), num_str);
588 }
589 else {
590 int frame_offset = std::trunc(offset);
591 if (data->show_subframe) {
592 float subframe_offset_sec = (offset - std::trunc(offset)) / FPS;
593 SNPRINTF(msg,
594 IFACE_("Slip Offset: Frames: %d Sound Offset: %.3f"),
595 frame_offset,
596 subframe_offset_sec);
597 }
598 else {
599 SNPRINTF(msg, IFACE_("Slip Offset: Frames: %d"), frame_offset);
600 }
601 }
602
603 ED_area_status_text(area, msg);
604}
605
606static SlipData *slip_data_init(const Scene *scene)
607{
608 Editing *ed = seq::editing_get(scene);
609 SlipData *data = MEM_new<SlipData>("slipdata");
610
613 strips.remove_if([&](Strip *strip) {
614 return ((strip->type & STRIP_TYPE_EFFECT) ||
616 seq::transform_is_locked(channels, strip));
617 });
618 if (strips.is_empty()) {
619 return nullptr;
620 }
621 data->strips = strips;
622
623 data->show_subframe = false;
624 data->clamp_warning = false;
625 data->can_clamp = false;
626
627 data->clamp = true;
628 for (Strip *strip : strips) {
629 strip->flag |= SEQ_SHOW_OFFSETS;
630
631 /* If any strips start out with hold offsets visible, disable clamping on initialization. */
632 if (strip->startofs < 0 || strip->endofs < 0) {
633 data->clamp = false;
634 }
635 /* If any strips do not have enough underlying content to
636 * fill their bounds, show a warning. */
637 if (strip->len < seq::time_right_handle_frame_get(scene, strip) -
639 {
640 data->clamp_warning = true;
641 }
642 /* Strip exists with enough content, we can clamp. */
643 else {
644 data->can_clamp = true;
645 }
646 if (strip->type == STRIP_TYPE_SOUND_RAM) {
647 data->show_subframe = true;
648 }
649 }
650
651 return data;
652}
653
655{
656 Scene *scene = CTX_data_scene(C);
657 ScrArea *area = CTX_wm_area(C);
659
660 SlipData *data = slip_data_init(scene);
661 if (data == nullptr) {
662 return OPERATOR_CANCELLED;
663 }
664 op->customdata = data;
665
666 initNumInput(&data->num_input);
668 v2d, event->mval[0], event->mval[1], &data->init_mouse_co[0], &data->init_mouse_co[1]);
669 data->precision = false;
670 data->prev_offset = 0.0f;
671 data->prev_mval_x = event->mval[0];
672 data->virtual_mval_x = event->mval[0];
673
674 slip_draw_status(C, op);
675 slip_update_header(scene, area, data, 0.0f);
676
678
679 /* Enable cursor wrapping. */
681
682 /* Notify so we draw extensions immediately. */
684
686}
687
688static void slip_strips_delta(wmOperator *op, Scene *scene, SlipData *data, const float delta)
689{
690 float new_offset = data->prev_offset + delta;
691 /* Calculate rounded whole frames between offsets, which cannot be determined from `delta` alone.
692 * For example, 0.9 -> 1.0 would have a `delta` of 0.1 and a `frame_delta` of 1. */
693 int frame_delta = std::trunc(new_offset) - std::trunc(data->prev_offset);
694
695 float subframe_delta = 0.0f;
696 /* Only apply subframe delta if the input is not an integer. */
697 if (std::trunc(delta) != delta) {
698 /* Note that `subframe_delta` has opposite sign to `frame_delta`
699 * when `abs(delta)` < `abs(frame_delta)` to undo its effect. */
700 subframe_delta = delta - frame_delta;
701 }
702
703 bool slip_keyframes = RNA_boolean_get(op->ptr, "slip_keyframes");
704 for (Strip *strip : data->strips) {
705 seq::time_slip_strip(scene, strip, frame_delta, subframe_delta, slip_keyframes);
707 }
708
709 RNA_float_set(op->ptr, "offset", new_offset);
710 data->prev_offset = new_offset;
711}
712
713static void slip_cleanup(bContext *C, wmOperator *op, Scene *scene)
714{
715 ScrArea *area = CTX_wm_area(C);
716 SlipData *data = static_cast<SlipData *>(op->customdata);
717
718 for (Strip *strip : data->strips) {
719 strip->flag &= ~SEQ_SHOW_OFFSETS;
720 }
721
722 MEM_SAFE_DELETE(data);
723 if (area) {
724 ED_area_status_text(area, nullptr);
725 }
726 ED_workspace_status_text(C, nullptr);
729}
730
731/* Returns clamped offset delta relative to current strip positions,
732 * which is the sum of the frame delta and the subframe delta. */
733static float slip_apply_clamp(const Scene *scene, const SlipData *data, float *r_offset)
734{
735 float offset_delta = *r_offset - data->prev_offset;
736
737 if (data->can_clamp) {
738 for (Strip *strip : data->strips) {
739 const float unclamped_start = seq::time_start_frame_get(strip) + strip->sound_offset +
740 offset_delta;
741 const float unclamped_end = seq::time_content_end_frame_get(scene, strip) +
742 strip->sound_offset + offset_delta;
743
744 const float left_handle = seq::time_left_handle_frame_get(scene, strip);
745 const float right_handle = seq::time_right_handle_frame_get(scene, strip);
746
747 float diff = 0;
748
749 /* Clamp hold offsets if the option is currently enabled
750 * and if there are enough frames to fill the strip. */
751 if (data->clamp && strip->len >= right_handle - left_handle) {
752 if (unclamped_start > left_handle) {
753 diff = left_handle - unclamped_start;
754 }
755 else if (unclamped_end < right_handle) {
756 diff = right_handle - unclamped_end;
757 }
758 }
759 /* Always make sure each strip contains at least 1 frame of content,
760 * even if the user hasn't enabled clamping. */
761 else {
762 if (unclamped_start > right_handle - 1) {
763 diff = right_handle - 1 - unclamped_start;
764 }
765
766 if (unclamped_end < left_handle + 1) {
767 diff = left_handle + 1 - unclamped_end;
768 }
769 }
770
771 *r_offset += diff;
772 offset_delta += diff;
773 }
774 }
775
776 return offset_delta;
777}
778
780{
781 Scene *scene = CTX_data_scene(C);
782
783 SlipData *data = slip_data_init(scene);
784 if (data == nullptr) {
785 return OPERATOR_CANCELLED;
786 }
787 op->customdata = data;
788
789 float offset = RNA_float_get(op->ptr, "offset");
790 slip_apply_clamp(scene, data, &offset);
791
792 slip_strips_delta(op, scene, data, offset);
793 slip_cleanup(C, op, scene);
794 return OPERATOR_FINISHED;
795}
796
798 const bContext *C, wmOperator *op, ScrArea *area, SlipData *data, Scene *scene)
799{
800 float offset;
801 applyNumInput(&data->num_input, &offset);
802
803 const float offset_delta = slip_apply_clamp(scene, data, &offset);
804 slip_update_header(scene, area, data, offset);
805 RNA_float_set(op->ptr, "offset", offset);
806
807 slip_strips_delta(op, scene, data, offset_delta);
808
810}
811
813{
815 Scene *scene = CTX_data_scene(C);
816 SlipData *data = static_cast<SlipData *>(op->customdata);
817 ScrArea *area = CTX_wm_area(C);
818 const bool has_num_input = hasNumInput(&data->num_input);
819
820 if (event->val == KM_PRESS && handleNumInput(C, &data->num_input, event)) {
821 slip_handle_num_input(C, op, area, data, scene);
823 }
824
825 if (event->type == EVT_MODAL_MAP) {
826 switch (event->val) {
827 case SLIP_MODAL_CONFIRM: {
828 slip_cleanup(C, op, scene);
829 return OPERATOR_FINISHED;
830 }
831 case SLIP_MODAL_CANCEL: {
832 slip_strips_delta(op, scene, data, -data->prev_offset);
833 slip_cleanup(C, op, scene);
834 return OPERATOR_CANCELLED;
835 }
837 if (!has_num_input) {
838 data->precision = true;
839 /* Align virtual mouse pointer with the truncated frame to avoid jumps. */
840 float mouse_co[2];
841 UI_view2d_region_to_view(v2d, data->virtual_mval_x, 0.0f, &mouse_co[0], &mouse_co[1]);
842 float offset = mouse_co[0] - data->init_mouse_co[0];
843 float subframe_offset = offset - std::trunc(offset);
844 data->virtual_mval_x += -subframe_offset * UI_view2d_scale_get_x(v2d);
845 }
846 break;
848 if (!has_num_input) {
849 data->precision = false;
850 /* If we exit precision mode, make sure we undo the fractional adjustments and align the
851 * virtual mouse pointer. */
852 float to_nearest_frame = -(data->prev_offset - round_fl_to_int(data->prev_offset));
853 slip_strips_delta(op, scene, data, to_nearest_frame);
854 data->virtual_mval_x += to_nearest_frame * UI_view2d_scale_get_x(v2d);
855 }
856 break;
858 data->clamp = !data->clamp;
859 break;
860 default:
861 break;
862 }
863 }
864
865 if (event->type == MOUSEMOVE || event->val == SLIP_MODAL_PRECISION_DISABLE ||
867 {
868 if (!has_num_input) {
869 float mouse_x_delta = event->mval[0] - data->prev_mval_x;
870 data->prev_mval_x += mouse_x_delta;
871 if (data->precision) {
872 mouse_x_delta *= 0.1f;
873 }
874 data->virtual_mval_x += mouse_x_delta;
875
876 float mouse_co[2];
877 UI_view2d_region_to_view(v2d, data->virtual_mval_x, 0.0f, &mouse_co[0], &mouse_co[1]);
878 float offset = mouse_co[0] - data->init_mouse_co[0];
879 if (!data->precision) {
880 offset = std::trunc(offset);
881 }
882
883 float clamped_offset = offset;
884 float clamped_offset_delta = slip_apply_clamp(scene, data, &clamped_offset);
885 /* Also adjust virtual mouse pointer after clamp is applied. */
886 data->virtual_mval_x += (clamped_offset - offset) * UI_view2d_scale_get_x(v2d);
887
888 slip_strips_delta(op, scene, data, clamped_offset_delta);
889 slip_update_header(scene, area, data, clamped_offset);
890
892 }
893 }
894
895 slip_draw_status(C, op);
896
898}
899
901{
902 /* Identifiers. */
903 ot->name = "Slip Strips";
904 ot->idname = "SEQUENCER_OT_slip";
905 ot->description = "Slip the contents of selected strips";
906
907 /* API callbacks. */
908 ot->invoke = sequencer_slip_invoke;
909 ot->modal = sequencer_slip_modal;
910 ot->exec = sequencer_slip_exec;
911 ot->poll = sequencer_edit_poll;
912
913 /* Flags. */
915
916 /* Properties. */
917 PropertyRNA *prop;
918
919 prop = RNA_def_float(ot->srna,
920 "offset",
921 0,
922 -FLT_MAX,
923 FLT_MAX,
924 "Offset",
925 "Offset to the data of the strip",
926 -FLT_MAX,
927 FLT_MAX);
929 RNA_def_boolean(ot->srna,
930 "slip_keyframes",
931 false,
932 "Slip Keyframes",
933 "Move the keyframes alongside the media");
934}
935
937
938/* -------------------------------------------------------------------- */
941
943{
944 Scene *scene = CTX_data_scene(C);
946
947 for (Strip *strip : strips) {
948 if (!RNA_boolean_get(op->ptr, "unselected")) {
949 if (strip->flag & SELECT) {
950 strip->flag |= SEQ_MUTE;
952 }
953 }
954 else {
955 if ((strip->flag & SELECT) == 0) {
956 strip->flag |= SEQ_MUTE;
958 }
959 }
960 }
961
964
965 return OPERATOR_FINISHED;
966}
967
969{
970 /* Identifiers. */
971 ot->name = "Mute Strips";
972 ot->idname = "SEQUENCER_OT_mute";
973 ot->description = "Mute (un)selected strips";
974
975 /* API callbacks. */
976 ot->exec = sequencer_mute_exec;
977 ot->poll = sequencer_edit_poll;
978
979 /* Flags. */
981
983 ot->srna, "unselected", false, "Unselected", "Mute unselected rather than selected strips");
984}
985
987
988/* -------------------------------------------------------------------- */
991
993{
994 Scene *scene = CTX_data_scene(C);
995 Editing *ed = seq::editing_get(scene);
996 ARegion *region = CTX_wm_region(C);
997 const bool is_preview = region && (region->regiontype == RGN_TYPE_PREVIEW) &&
999 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
1000 if (is_preview) {
1001 if (seq::time_strip_intersects_frame(scene, strip, scene->r.cfra) &&
1002 strip->type != STRIP_TYPE_SOUND_RAM)
1003 {
1004 strip->flag &= ~SEQ_MUTE;
1005 seq::relations_invalidate_cache(scene, strip);
1006 }
1007 }
1008 else if (!RNA_boolean_get(op->ptr, "unselected")) {
1009 if (strip->flag & SELECT) {
1010 strip->flag &= ~SEQ_MUTE;
1011 seq::relations_invalidate_cache(scene, strip);
1012 }
1013 }
1014 else {
1015 if ((strip->flag & SELECT) == 0) {
1016 strip->flag &= ~SEQ_MUTE;
1017 seq::relations_invalidate_cache(scene, strip);
1018 }
1019 }
1020 }
1021
1024
1025 return OPERATOR_FINISHED;
1026}
1027
1029{
1030 /* Identifiers. */
1031 ot->name = "Unmute Strips";
1032 ot->idname = "SEQUENCER_OT_unmute";
1033 ot->description = "Unmute (un)selected strips";
1034
1035 /* API callbacks. */
1036 ot->exec = sequencer_unmute_exec;
1037 ot->poll = sequencer_edit_poll;
1038
1039 /* Flags. */
1040 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1041
1042 RNA_def_boolean(ot->srna,
1043 "unselected",
1044 false,
1045 "Unselected",
1046 "Unmute unselected rather than selected strips");
1047}
1048
1050
1051/* -------------------------------------------------------------------- */
1054
1056{
1057 Scene *scene = CTX_data_scene(C);
1058 Editing *ed = seq::editing_get(scene);
1059
1060 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
1061 if (strip->flag & SELECT) {
1062 strip->flag |= SEQ_LOCK;
1063 }
1064 }
1065
1067
1068 return OPERATOR_FINISHED;
1069}
1070
1072{
1073 /* Identifiers. */
1074 ot->name = "Lock Strips";
1075 ot->idname = "SEQUENCER_OT_lock";
1076 ot->description = "Lock strips so they can't be transformed";
1077
1078 /* API callbacks. */
1079 ot->exec = sequencer_lock_exec;
1080 ot->poll = sequencer_edit_poll;
1081
1082 /* Flags. */
1083 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1084}
1085
1087
1088/* -------------------------------------------------------------------- */
1091
1093{
1094 Scene *scene = CTX_data_scene(C);
1095 Editing *ed = seq::editing_get(scene);
1096
1097 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
1098 if (strip->flag & SELECT) {
1099 strip->flag &= ~SEQ_LOCK;
1100 }
1101 }
1102
1104
1105 return OPERATOR_FINISHED;
1106}
1107
1109{
1110 /* Identifiers. */
1111 ot->name = "Unlock Strips";
1112 ot->idname = "SEQUENCER_OT_unlock";
1113 ot->description = "Unlock strips so they can be transformed";
1114
1115 /* API callbacks. */
1116 ot->exec = sequencer_unlock_exec;
1117 ot->poll = sequencer_edit_poll;
1118
1119 /* Flags. */
1120 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1121}
1122
1124
1125/* -------------------------------------------------------------------- */
1128
1130{
1131 Scene *scene = CTX_data_scene(C);
1132 Editing *ed = seq::editing_get(scene);
1133 ListBase *active_seqbase = seq::active_seqbase_get(ed);
1134
1136
1137 if (selected.is_empty()) {
1138 return OPERATOR_CANCELLED;
1139 }
1140
1141 const bool toggle = RNA_boolean_get(op->ptr, "toggle");
1142 if (toggle && seq::are_strips_connected_together(selected)) {
1143 seq::disconnect(selected);
1144 }
1145 else {
1146 seq::connect(selected);
1147 }
1148
1150 return OPERATOR_FINISHED;
1151}
1152
1154{
1155 ot->name = "Connect Strips";
1156 ot->idname = "SEQUENCER_OT_connect";
1157 ot->description = "Link selected strips together for simplified group selection";
1158
1159 ot->exec = sequencer_connect_exec;
1160 ot->poll = sequencer_edit_poll;
1161
1162 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1163
1164 RNA_def_boolean(ot->srna, "toggle", true, "Toggle", "Toggle strip connections");
1165}
1166
1168
1169/* -------------------------------------------------------------------- */
1172
1174{
1175 Scene *scene = CTX_data_scene(C);
1176 Editing *ed = seq::editing_get(scene);
1177 ListBase *active_seqbase = seq::active_seqbase_get(ed);
1178
1180
1181 if (seq::disconnect(selected)) {
1183 return OPERATOR_FINISHED;
1184 }
1185 return OPERATOR_CANCELLED;
1186}
1187
1189{
1190 ot->name = "Disconnect Strips";
1191 ot->idname = "SEQUENCER_OT_disconnect";
1192 ot->description = "Unlink selected strips so that they can be selected individually";
1193
1195 ot->poll = sequencer_edit_poll;
1196
1197 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1198}
1199
1201
1202/* -------------------------------------------------------------------- */
1205
1207{
1208 Main *bmain = CTX_data_main(C);
1209 Scene *scene = CTX_data_scene(C);
1210 Editing *ed = seq::editing_get(scene);
1211 const bool adjust_length = RNA_boolean_get(op->ptr, "adjust_length");
1212
1213 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
1214 if (strip->flag & SELECT) {
1215 seq::add_reload_new_file(bmain, scene, strip, !adjust_length);
1217
1218 if (adjust_length) {
1219 if (seq::transform_test_overlap(scene, ed->seqbasep, strip)) {
1220 seq::transform_seqbase_shuffle(ed->seqbasep, strip, scene);
1221 }
1222 }
1223 }
1224 }
1225
1227
1228 return OPERATOR_FINISHED;
1229}
1230
1232{
1233 PropertyRNA *prop;
1234
1235 /* Identifiers. */
1236 ot->name = "Reload Strips";
1237 ot->idname = "SEQUENCER_OT_reload";
1238 ot->description = "Reload strips in the sequencer";
1239
1240 /* API callbacks. */
1241 ot->exec = sequencer_reload_exec;
1242 ot->poll = sequencer_edit_poll;
1243
1244 /* Flags. */
1245 ot->flag = OPTYPE_REGISTER; /* No undo, the data changed is stored outside 'main'. */
1246
1247 prop = RNA_def_boolean(ot->srna,
1248 "adjust_length",
1249 false,
1250 "Adjust Length",
1251 "Adjust length of strips to their data length");
1253}
1254
1256
1257/* -------------------------------------------------------------------- */
1260
1262{
1263 if (G.is_rendering) {
1264 return false;
1265 }
1266 return sequencer_edit_poll(C);
1267}
1268
1270{
1271 Scene *scene = CTX_data_scene(C);
1272 Editing *ed = seq::editing_get(scene);
1273
1274 seq::relations_free_imbuf(scene, &ed->seqbase, false);
1276 seq::cache_cleanup(scene);
1277
1279
1280 return OPERATOR_FINISHED;
1281}
1282
1284{
1285 /* Identifiers. */
1286 ot->name = "Refresh Sequencer";
1287 ot->idname = "SEQUENCER_OT_refresh_all";
1288 ot->description = "Refresh the sequencer editor";
1289
1290 /* API callbacks. */
1293}
1294
1296
1297/* -------------------------------------------------------------------- */
1300
1302{
1303 if (inputs.size() > 2) {
1304 return "Cannot apply effect to more than 2 strips with video content";
1305 }
1306 if (num_inputs == 2 && inputs.size() != 2) {
1307 return "Exactly 2 selected strips with video content are needed";
1308 }
1309 if (num_inputs == 1 && inputs.size() != 1) {
1310 return "Exactly one selected strip with video content is needed";
1311 }
1312 return "";
1313}
1314
1316 int num_inputs,
1317 bool ignore_active)
1318{
1319 if (num_inputs == 0) {
1320 return {};
1321 }
1322
1323 Editing *ed = seq::editing_get(scene);
1324 blender::VectorSet<Strip *> selected_strips = seq::query_selected_strips(ed->seqbasep);
1325 /* Ignore sound strips for now (avoids unnecessary errors when connected strips are
1326 * selected together, and the intent to operate on strips with video content is clear). */
1327 selected_strips.remove_if([&](Strip *strip) { return strip->type == STRIP_TYPE_SOUND_RAM; });
1328
1329 if (ignore_active) {
1330 /* If `ignore_active` is true, this function is being called from the reassign inputs
1331 * operator, meaning the active strip must be the effect strip to reassign. */
1332 Strip *active_strip = seq::select_active_get(scene);
1333 selected_strips.remove_if([&](Strip *strip) { return strip == active_strip; });
1334 }
1335
1336 if (selected_strips.size() > num_inputs) {
1338 for (int64_t i : IndexRange(num_inputs)) {
1339 inputs.add(selected_strips[i]);
1340 }
1341 return inputs;
1342 }
1343
1344 return selected_strips;
1345}
1346
1348{
1349 Scene *scene = CTX_data_scene(C);
1350 Strip *active_strip = seq::select_active_get(scene);
1351 const int num_inputs = seq::effect_get_num_inputs(active_strip->type);
1352
1353 if (num_inputs == 0) {
1354 BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: strip has no inputs");
1355 return OPERATOR_CANCELLED;
1356 }
1357
1358 VectorSet<Strip *> inputs = strip_effect_get_new_inputs(scene, num_inputs, true);
1359 StringRef error_msg = effect_inputs_validate(inputs, num_inputs);
1360
1361 if (!error_msg.is_empty()) {
1362 BKE_report(op->reports, RPT_ERROR, error_msg.data());
1363 return OPERATOR_CANCELLED;
1364 }
1365
1366 Strip *input1 = inputs[0];
1367 Strip *input2 = inputs.size() == 2 ? inputs[1] : nullptr;
1368
1369 /* Check if reassigning would create recursivity. */
1370 if (seq::relations_render_loop_check(input1, active_strip) ||
1371 seq::relations_render_loop_check(input2, active_strip))
1372 {
1373 BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: recursion detected");
1374 return OPERATOR_CANCELLED;
1375 }
1376
1377 active_strip->input1 = input1;
1378 active_strip->input2 = input2;
1379
1380 int old_start = active_strip->start;
1381
1382 /* Force time position update for reassigned effects.
1383 * TODO(Richard): This is because internally startdisp is still used, due to poor performance
1384 * of mapping effect range to inputs. This mapping could be cached though. */
1387
1388 seq::relations_invalidate_cache(scene, active_strip);
1389 seq::offset_animdata(scene, active_strip, (active_strip->start - old_start));
1390
1392
1393 return OPERATOR_FINISHED;
1394}
1395
1397{
1398 /* Identifiers. */
1399 ot->name = "Reassign Inputs";
1400 ot->idname = "SEQUENCER_OT_reassign_inputs";
1401 ot->description = "Reassign the inputs for the effect strip";
1402
1403 /* API callbacks. */
1405 ot->poll = sequencer_effect_poll;
1406
1407 /* Flags. */
1408 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1409}
1410
1412
1413/* -------------------------------------------------------------------- */
1416
1418{
1419 Scene *scene = CTX_data_scene(C);
1420 Strip *active_strip = seq::select_active_get(scene);
1421
1422 if (!(active_strip->type & STRIP_TYPE_EFFECT)) {
1423 BKE_report(op->reports, RPT_ERROR, "Active strip is not an effect strip");
1424 return OPERATOR_CANCELLED;
1425 }
1426
1427 if (seq::effect_get_num_inputs(active_strip->type) != 2 || active_strip->input1 == nullptr ||
1428 active_strip->input2 == nullptr)
1429 {
1430 BKE_report(op->reports, RPT_ERROR, "Strip needs two inputs to swap");
1431 return OPERATOR_CANCELLED;
1432 }
1433
1434 Strip *strip = active_strip->input1;
1435 active_strip->input1 = active_strip->input2;
1436 active_strip->input2 = strip;
1437
1438 seq::relations_invalidate_cache(scene, active_strip);
1440
1441 return OPERATOR_FINISHED;
1442}
1444{
1445 /* Identifiers. */
1446 ot->name = "Swap Inputs";
1447 ot->idname = "SEQUENCER_OT_swap_inputs";
1448 ot->description = "Swap the two inputs of the effect strip";
1449
1450 /* API callbacks. */
1453
1454 /* Flags. */
1455 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1456}
1457
1459
1460/* -------------------------------------------------------------------- */
1463
1464static int mouse_frame_side(View2D *v2d, short mouse_x, int frame)
1465{
1466 int mval[2];
1467 float mouseloc[2];
1468
1469 mval[0] = mouse_x;
1470 mval[1] = 0;
1471
1472 /* Choose the side based on which side of the current frame the mouse is on. */
1473 UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseloc[0], &mouseloc[1]);
1474
1475 return mouseloc[0] > frame ? seq::SIDE_RIGHT : seq::SIDE_LEFT;
1476}
1477
1479 {seq::SPLIT_SOFT, "SOFT", 0, "Soft", ""},
1480 {seq::SPLIT_HARD, "HARD", 0, "Hard", ""},
1481 {0, nullptr, 0, nullptr, nullptr},
1482};
1483
1485 {seq::SIDE_MOUSE, "MOUSE", 0, "Mouse Position", ""},
1486 {seq::SIDE_LEFT, "LEFT", 0, "Left", ""},
1487 {seq::SIDE_RIGHT, "RIGHT", 0, "Right", ""},
1488 {seq::SIDE_BOTH, "BOTH", 0, "Both", ""},
1489 {seq::SIDE_NO_CHANGE, "NO_CHANGE", 0, "No Change", ""},
1490 {0, nullptr, 0, nullptr, nullptr},
1491};
1492
1493/* Get the splitting side for the Split Strips's operator exec() callback. */
1495{
1496 const int split_side = RNA_enum_get(op->ptr, "side");
1497
1498 /* The mouse position can not be resolved from the exec() as the mouse coordinate is not
1499 * accessible. So fall-back to the RIGHT side instead.
1500 *
1501 * The SEQ_SIDE_MOUSE is used by the Strip menu, together with the EXEC_DEFAULT operator
1502 * context in order to have properly resolved shortcut in the menu. */
1503 if (split_side == seq::SIDE_MOUSE) {
1504 return seq::SIDE_RIGHT;
1505 }
1506
1507 return split_side;
1508}
1509
1511{
1512 Main *bmain = CTX_data_main(C);
1513 Scene *scene = CTX_data_scene(C);
1514 Editing *ed = seq::editing_get(scene);
1515 bool changed = false;
1516 bool strip_selected = false;
1517
1518 const bool use_cursor_position = RNA_boolean_get(op->ptr, "use_cursor_position");
1519
1520 const int split_frame = RNA_struct_property_is_set(op->ptr, "frame") ?
1521 RNA_int_get(op->ptr, "frame") :
1522 scene->r.cfra;
1523 const int split_channel = RNA_int_get(op->ptr, "channel");
1524
1525 const seq::eSplitMethod method = seq::eSplitMethod(RNA_enum_get(op->ptr, "type"));
1526 const int split_side = sequence_split_side_for_exec_get(op);
1527 const bool ignore_selection = RNA_boolean_get(op->ptr, "ignore_selection");
1528 const bool ignore_connections = RNA_boolean_get(op->ptr, "ignore_connections");
1529
1530 seq::prefetch_stop(scene);
1531
1532 LISTBASE_FOREACH_BACKWARD (Strip *, strip, ed->seqbasep) {
1533 if (use_cursor_position && strip->channel != split_channel) {
1534 continue;
1535 }
1536
1537 if (ignore_selection || strip->flag & SELECT) {
1538 const char *error_msg = nullptr;
1539 if (seq::edit_strip_split(bmain,
1540 scene,
1541 ed->seqbasep,
1542 strip,
1543 split_frame,
1544 method,
1545 ignore_connections,
1546 &error_msg) != nullptr)
1547 {
1548 changed = true;
1549 }
1550 if (error_msg != nullptr) {
1551 BKE_report(op->reports, RPT_ERROR, error_msg);
1552 }
1553 }
1554 }
1555
1556 if (changed) { /* Got new strips? */
1557 if (ignore_selection) {
1558 if (use_cursor_position) {
1560 if (seq::time_right_handle_frame_get(scene, strip) == split_frame &&
1561 strip->channel == split_channel)
1562 {
1563 strip_selected = strip->flag & STRIP_ALLSEL;
1564 }
1565 }
1566 if (!strip_selected) {
1568 if (seq::time_left_handle_frame_get(scene, strip) == split_frame &&
1569 strip->channel == split_channel)
1570 {
1571 strip->flag &= ~STRIP_ALLSEL;
1572 }
1573 }
1574 }
1575 }
1576 }
1577 else {
1578 if (split_side != seq::SIDE_BOTH) {
1580 if (split_side == seq::SIDE_LEFT) {
1581 if (seq::time_left_handle_frame_get(scene, strip) >= split_frame) {
1582 strip->flag &= ~STRIP_ALLSEL;
1583 }
1584 }
1585 else {
1586 if (seq::time_right_handle_frame_get(scene, strip) <= split_frame) {
1587 strip->flag &= ~STRIP_ALLSEL;
1588 }
1589 }
1590 }
1591 }
1592 }
1593 }
1594 if (changed) {
1596 return OPERATOR_FINISHED;
1597 }
1598
1599 /* Passthrough to selection if used as tool. */
1601}
1602
1604{
1605 Scene *scene = CTX_data_scene(C);
1607
1608 int split_side = RNA_enum_get(op->ptr, "side");
1609 int split_frame = scene->r.cfra;
1610
1611 if (split_side == seq::SIDE_MOUSE) {
1612 if (ED_operator_sequencer_active(C) && v2d) {
1613 split_side = mouse_frame_side(v2d, event->mval[0], split_frame);
1614 }
1615 else {
1616 split_side = seq::SIDE_BOTH;
1617 }
1618 }
1619 float mouseloc[2];
1620 if (v2d) {
1621 UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]);
1622 if (RNA_boolean_get(op->ptr, "use_cursor_position")) {
1623 split_frame = round_fl_to_int(mouseloc[0]);
1624 Strip *strip = strip_under_mouse_get(scene, v2d, event->mval);
1625 if (strip == nullptr || split_frame == seq::time_left_handle_frame_get(scene, strip) ||
1626 split_frame == seq::time_right_handle_frame_get(scene, strip))
1627 {
1628 /* Do not pass through to selection. */
1629 return OPERATOR_CANCELLED;
1630 }
1631 }
1632 RNA_int_set(op->ptr, "channel", mouseloc[1]);
1633 }
1634 RNA_int_set(op->ptr, "frame", split_frame);
1635 RNA_enum_set(op->ptr, "side", split_side);
1636 // RNA_enum_set(op->ptr, "type", split_hard);
1637
1638 return sequencer_split_exec(C, op);
1639}
1640
1641static void sequencer_split_ui(bContext * /*C*/, wmOperator *op)
1642{
1643 uiLayout *layout = op->layout;
1644 uiLayoutSetPropSep(layout, true);
1645 uiLayoutSetPropDecorate(layout, false);
1646
1647 uiLayout *row = &layout->row(false);
1648 row->prop(op->ptr, "type", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
1649 layout->prop(op->ptr, "frame", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1650 layout->prop(op->ptr, "side", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1651
1652 layout->separator();
1653
1654 layout->prop(op->ptr, "use_cursor_position", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1655 if (RNA_boolean_get(op->ptr, "use_cursor_position")) {
1656 layout->prop(op->ptr, "channel", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1657 }
1658
1659 layout->separator();
1660
1661 layout->prop(op->ptr, "ignore_connections", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1662}
1663
1665{
1666 /* Identifiers. */
1667 ot->name = "Split Strips";
1668 ot->idname = "SEQUENCER_OT_split";
1669 ot->description = "Split the selected strips in two";
1670
1671 /* API callbacks. */
1672 ot->invoke = sequencer_split_invoke;
1673 ot->exec = sequencer_split_exec;
1674 ot->poll = sequencer_edit_poll;
1675 ot->ui = sequencer_split_ui;
1676
1677 /* Flags. */
1678 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1679
1680 PropertyRNA *prop;
1681 RNA_def_int(ot->srna,
1682 "frame",
1683 0,
1684 INT_MIN,
1685 INT_MAX,
1686 "Frame",
1687 "Frame where selected strips will be split",
1688 INT_MIN,
1689 INT_MAX);
1690 RNA_def_int(ot->srna,
1691 "channel",
1692 0,
1693 INT_MIN,
1694 INT_MAX,
1695 "Channel",
1696 "Channel in which strip will be cut",
1697 INT_MIN,
1698 INT_MAX);
1699 RNA_def_enum(ot->srna,
1700 "type",
1703 "Type",
1704 "The type of split operation to perform on strips");
1705
1706 RNA_def_boolean(ot->srna,
1707 "use_cursor_position",
1708 false,
1709 "Use Cursor Position",
1710 "Split at position of the cursor instead of current frame");
1711
1712 prop = RNA_def_enum(ot->srna,
1713 "side",
1716 "Side",
1717 "The side that remains selected after splitting");
1718
1720
1721 prop = RNA_def_boolean(
1722 ot->srna,
1723 "ignore_selection",
1724 false,
1725 "Ignore Selection",
1726 "Make cut even if strip is not selected preserving selection state after cut");
1727
1729
1730 RNA_def_boolean(ot->srna,
1731 "ignore_connections",
1732 false,
1733 "Ignore Connections",
1734 "Don't propagate split to connected strips");
1735}
1736
1738
1739/* -------------------------------------------------------------------- */
1742
1744{
1745 Scene *scene = CTX_data_scene(C);
1746 Editing *ed = seq::editing_get(scene);
1747 ARegion *region = CTX_wm_region(C);
1748
1749 if (ed == nullptr) {
1750 return OPERATOR_CANCELLED;
1751 }
1752
1753 Strip *active_strip = seq::select_active_get(scene);
1754 ListBase duplicated_strips = {nullptr, nullptr};
1755
1756 /* Special case for duplicating strips in preview: Do not duplicate sound strips,muted
1757 * strips and strips that do not intersect the current frame */
1759 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
1760 if (strip->type == STRIP_TYPE_SOUND_RAM || strip->flag & SEQ_MUTE ||
1761 !(seq::time_strip_intersects_frame(scene, strip, scene->r.cfra)))
1762 {
1763 strip->flag &= ~STRIP_ALLSEL;
1764 }
1765 }
1766 }
1767
1768 seq::seqbase_duplicate_recursive(scene, scene, &duplicated_strips, ed->seqbasep, 0, 0);
1769 deselect_all_strips(scene);
1770
1771 if (duplicated_strips.first == nullptr) {
1772 return OPERATOR_CANCELLED;
1773 }
1774
1775 /* Duplicate animation.
1776 * First backup original curves from scene and duplicate strip curves from backup into scene.
1777 * This way, when pasted strips are renamed, curves are renamed with them. Finally, restore
1778 * original curves from backup.
1779 */
1780 seq::AnimationBackup animation_backup = {{nullptr}};
1781 seq::animation_backup_original(scene, &animation_backup);
1782
1784 Strip *strip_last = static_cast<Strip *>(seqbase->last);
1785
1786 /* Rely on the `duplicated_strips` list being added at the end.
1787 * Their UIDs has been re-generated by the #SEQ_sequence_base_dupli_recursive(). */
1788 BLI_movelisttolist(ed->seqbasep, &duplicated_strips);
1789
1790 /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation
1791 * data. */
1792 for (Strip *strip = strip_last->next; strip; strip = strip->next) {
1793 if (active_strip != nullptr && STREQ(strip->name, active_strip->name)) {
1794 seq::select_active_set(scene, strip);
1795 }
1796 strip->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
1797 strip->flag |= SEQ_IGNORE_CHANNEL_LOCK;
1798
1799 seq::animation_duplicate_backup_to_scene(scene, strip, &animation_backup);
1800 seq::ensure_unique_name(strip, scene);
1801 }
1802
1803 /* Special case for duplicating strips in preview: handle overlap, because strips won't be
1804 * translated. */
1806 for (Strip *strip = strip_last->next; strip; strip = strip->next) {
1807 if (seq::transform_test_overlap(scene, ed->seqbasep, strip)) {
1808 seq::transform_seqbase_shuffle(ed->seqbasep, strip, scene);
1809 }
1810 strip->flag &= ~SEQ_IGNORE_CHANNEL_LOCK;
1811 }
1812 }
1813
1814 seq::animation_restore_original(scene, &animation_backup);
1815
1819 return OPERATOR_FINISHED;
1820}
1821
1823{
1824 /* Identifiers. */
1825 ot->name = "Duplicate Strips";
1826 ot->idname = "SEQUENCER_OT_duplicate";
1827 ot->description = "Duplicate the selected strips";
1828
1829 /* API callbacks. */
1832
1833 /* Flags. */
1834 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1835}
1836
1838
1839/* -------------------------------------------------------------------- */
1842
1844{
1845 if (strip->type != STRIP_TYPE_SCENE) {
1846 return;
1847 }
1848
1849 Main *bmain = CTX_data_main(C);
1850 if (strip->scene) {
1851 if (ED_scene_delete(C, bmain, strip->scene)) {
1853 }
1854 }
1855}
1856
1858{
1859 Main *bmain = CTX_data_main(C);
1860 Scene *scene = CTX_data_scene(C);
1862 const bool delete_data = RNA_boolean_get(op->ptr, "delete_data");
1863
1865 return OPERATOR_CANCELLED;
1866 }
1867
1868 seq::prefetch_stop(scene);
1869
1870 for (Strip *strip : selected_strips_from_context(C)) {
1871 seq::edit_flag_for_removal(scene, seqbasep, strip);
1872 if (delete_data) {
1874 }
1875 }
1876 seq::edit_remove_flagged_strips(scene, seqbasep);
1877
1879 if (scene->adt && scene->adt->action) {
1881 }
1885 return OPERATOR_FINISHED;
1886}
1887
1889{
1890 Scene *scene = CTX_data_scene(C);
1891 ListBase *markers = &scene->markers;
1892
1893 if (!BLI_listbase_is_empty(markers)) {
1894 ARegion *region = CTX_wm_region(C);
1895 if (region && (region->regiontype == RGN_TYPE_WINDOW)) {
1896 /* Bounding box of 30 pixels is used for markers shortcuts,
1897 * prevent conflict with markers shortcuts here. */
1898 if (event->mval[1] <= 30) {
1899 return OPERATOR_PASS_THROUGH;
1900 }
1901 }
1902 }
1903
1904 return sequencer_delete_exec(C, op);
1905}
1906
1908{
1909 /* Identifiers. */
1910 ot->name = "Delete Strips";
1911 ot->idname = "SEQUENCER_OT_delete";
1912 ot->description = "Delete selected strips from the sequencer";
1913
1914 /* API callbacks. */
1915 ot->invoke = sequencer_delete_invoke;
1916 ot->exec = sequencer_delete_exec;
1917 ot->poll = sequencer_edit_poll;
1918
1919 /* Flags. */
1920 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1921
1922 /* Properties. */
1923 ot->prop = RNA_def_boolean(ot->srna,
1924 "delete_data",
1925 false,
1926 "Delete Data",
1927 "After removing the Strip, delete the associated data also");
1929}
1930
1932
1933/* -------------------------------------------------------------------- */
1936
1938{
1939 Scene *scene = CTX_data_scene(C);
1940 Editing *ed = seq::editing_get(scene);
1941 Strip *strip;
1943
1944 /* For effects, try to find a replacement input. */
1945 for (strip = static_cast<Strip *>(ed->seqbasep->first); strip;
1946 strip = static_cast<Strip *>(strip->next))
1947 {
1948 if (seq::transform_is_locked(channels, strip)) {
1949 continue;
1950 }
1951
1952 if ((strip->type & STRIP_TYPE_EFFECT) == 0 && (strip->flag & SELECT)) {
1953 strip->startofs = strip->endofs = 0;
1954 }
1955 }
1956
1957 /* Update lengths, etc. */
1958 strip = static_cast<Strip *>(ed->seqbasep->first);
1959 while (strip) {
1960 seq::relations_invalidate_cache(scene, strip);
1961 strip = strip->next;
1962 }
1963
1964 for (strip = static_cast<Strip *>(ed->seqbasep->first); strip;
1965 strip = static_cast<Strip *>(strip->next))
1966 {
1967 if ((strip->type & STRIP_TYPE_EFFECT) == 0 && (strip->flag & SELECT)) {
1968 if (seq::transform_test_overlap(scene, ed->seqbasep, strip)) {
1969 seq::transform_seqbase_shuffle(ed->seqbasep, strip, scene);
1970 }
1971 }
1972 }
1973
1975
1976 return OPERATOR_FINISHED;
1977}
1978
1980{
1981 /* Identifiers. */
1982 ot->name = "Clear Strip Offset";
1983 ot->idname = "SEQUENCER_OT_offset_clear";
1984 ot->description = "Clear strip offsets from the start and end frames";
1985
1986 /* API callbacks. */
1988 ot->poll = sequencer_edit_poll;
1989
1990 /* Flags. */
1991 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1992}
1993
1995
1996/* -------------------------------------------------------------------- */
1999
2001{
2002 Scene *scene = CTX_data_scene(C);
2003 Editing *ed = seq::editing_get(scene);
2005
2006 Strip *strip, *strip_new;
2007 StripData *data_new;
2008 StripElem *se, *se_new;
2009 int start_ofs, timeline_frame, frame_end;
2010 int step = RNA_int_get(op->ptr, "length");
2011
2012 strip = static_cast<Strip *>(seqbase->first); /* Poll checks this is valid. */
2013
2014 seq::prefetch_stop(scene);
2015
2016 while (strip) {
2017 if ((strip->flag & SELECT) && (strip->type == STRIP_TYPE_IMAGE) && (strip->len > 1)) {
2018 Strip *strip_next;
2019
2020 /* TODO: remove f-curve and assign to split image strips.
2021 * The old animation system would remove the user of `strip->ipo`. */
2022
2023 start_ofs = timeline_frame = seq::time_left_handle_frame_get(scene, strip);
2024 frame_end = seq::time_right_handle_frame_get(scene, strip);
2025
2026 while (timeline_frame < frame_end) {
2027 /* New strip. */
2028 se = seq::render_give_stripelem(scene, strip, timeline_frame);
2029
2031 scene, scene, seqbase, strip, STRIP_DUPE_UNIQUE_NAME);
2032
2033 strip_new->start = start_ofs;
2034 strip_new->type = STRIP_TYPE_IMAGE;
2035 strip_new->len = 1;
2036 strip_new->flag |= SEQ_SINGLE_FRAME_CONTENT;
2037 strip_new->endofs = 1 - step;
2038
2039 /* New strip. */
2040 data_new = strip_new->data;
2041 data_new->us = 1;
2042
2043 /* New stripdata, only one element now. */
2044 /* Note this assume all elements (images) have the same dimension,
2045 * since we only copy the name here. */
2046 se_new = static_cast<StripElem *>(MEM_reallocN(data_new->stripdata, sizeof(*se_new)));
2047 STRNCPY(se_new->filename, se->filename);
2048 data_new->stripdata = se_new;
2049
2050 if (step > 1) {
2051 strip_new->flag &= ~SEQ_OVERLAP;
2052 if (seq::transform_test_overlap(scene, seqbase, strip_new)) {
2053 seq::transform_seqbase_shuffle(seqbase, strip_new, scene);
2054 }
2055 }
2056
2057 /* XXX, COPY FCURVES */
2058
2059 timeline_frame++;
2060 start_ofs += step;
2061 }
2062
2063 strip_next = static_cast<Strip *>(strip->next);
2064 seq::edit_flag_for_removal(scene, seqbase, strip);
2065 strip = strip_next;
2066 }
2067 else {
2068 strip = strip->next;
2069 }
2070 }
2071
2072 seq::edit_remove_flagged_strips(scene, seqbase);
2074
2075 return OPERATOR_FINISHED;
2076}
2077
2079 wmOperator *op,
2080 const wmEvent *event)
2081{
2083 C, op, event, IFACE_("Separate Sequence Images"), IFACE_("Separate"));
2084}
2085
2087{
2088 /* Identifiers. */
2089 ot->name = "Separate Images";
2090 ot->idname = "SEQUENCER_OT_images_separate";
2091 ot->description = "On image sequence strips, it returns a strip for each image";
2092
2093 /* API callbacks. */
2096 ot->poll = sequencer_edit_poll;
2097
2098 /* Flags. */
2099 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2100
2101 RNA_def_int(ot->srna, "length", 1, 1, INT_MAX, "Length", "Length of each frame", 1, 1000);
2102}
2103
2105
2106/* -------------------------------------------------------------------- */
2109
2111{
2112 Scene *scene = CTX_data_scene(C);
2113 Editing *ed = seq::editing_get(scene);
2114 Strip *active_strip = seq::select_active_get(scene);
2115
2116 seq::prefetch_stop(scene);
2117
2118 if (active_strip && active_strip->type == STRIP_TYPE_META && active_strip->flag & SELECT) {
2119 /* Deselect active meta strip. */
2120 seq::select_active_set(scene, nullptr);
2121 seq::meta_stack_set(scene, active_strip);
2122 }
2123 else {
2124 /* Exit meta-strip if possible. */
2125 if (BLI_listbase_is_empty(&ed->metastack)) {
2126 return OPERATOR_CANCELLED;
2127 }
2128
2129 /* Display parent meta. */
2130 Strip *meta_parent = seq::meta_stack_pop(ed);
2131 seq::select_active_set(scene, meta_parent);
2132 }
2133
2136
2137 return OPERATOR_FINISHED;
2138}
2139
2141{
2142 /* Identifiers. */
2143 ot->name = "Toggle Meta Strip";
2144 ot->idname = "SEQUENCER_OT_meta_toggle";
2145 ot->description = "Toggle a meta-strip (to edit enclosed strips)";
2146
2147 /* API callbacks. */
2149 ot->poll = sequencer_edit_poll;
2150
2151 /* Flags. */
2152 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2153}
2154
2156
2157/* -------------------------------------------------------------------- */
2160
2162{
2163 Scene *scene = CTX_data_scene(C);
2164 Editing *ed = seq::editing_get(scene);
2165 Strip *active_strip = seq::select_active_get(scene);
2166 ListBase *active_seqbase = seq::active_seqbase_get(ed);
2167
2169
2170 if (selected.is_empty()) {
2171 return OPERATOR_CANCELLED;
2172 }
2173
2174 seq::prefetch_stop(scene);
2175
2176 int channel_max = 1, channel_min = INT_MAX, meta_start_frame = MAXFRAME,
2177 meta_end_frame = MINFRAME;
2178 Strip *strip_meta = seq::strip_alloc(active_seqbase, 1, 1, STRIP_TYPE_META);
2179
2180 /* Remove all selected from main list, and put in meta.
2181 * Strip is moved within the same edit, no need to re-generate the UID. */
2182 blender::VectorSet<Strip *> strips_to_move;
2183 strips_to_move.add_multiple(selected);
2185 scene, active_seqbase, strips_to_move, seq::query_strip_connected_and_effect_chain);
2186
2187 for (Strip *strip : strips_to_move) {
2188 seq::relations_invalidate_cache(scene, strip);
2189 BLI_remlink(active_seqbase, strip);
2190 BLI_addtail(&strip_meta->seqbase, strip);
2191 channel_max = max_ii(strip->channel, channel_max);
2192 channel_min = min_ii(strip->channel, channel_min);
2193 meta_start_frame = min_ii(seq::time_left_handle_frame_get(scene, strip), meta_start_frame);
2194 meta_end_frame = max_ii(seq::time_right_handle_frame_get(scene, strip), meta_end_frame);
2195 }
2196
2197 ListBase *channels_cur = seq::channels_displayed_get(ed);
2198 ListBase *channels_meta = &strip_meta->channels;
2199 for (int i = channel_min; i <= channel_max; i++) {
2200 SeqTimelineChannel *channel_cur = seq::channel_get_by_index(channels_cur, i);
2201 SeqTimelineChannel *channel_meta = seq::channel_get_by_index(channels_meta, i);
2202 STRNCPY(channel_meta->name, channel_cur->name);
2203 channel_meta->flag = channel_cur->flag;
2204 }
2205
2206 const int channel = active_strip ? active_strip->channel : channel_max;
2207 seq::strip_channel_set(strip_meta, channel);
2208 BLI_strncpy(strip_meta->name + 2, DATA_("MetaStrip"), sizeof(strip_meta->name) - 2);
2209 seq::strip_unique_name_set(scene, &ed->seqbase, strip_meta);
2210 strip_meta->start = meta_start_frame;
2211 strip_meta->len = meta_end_frame - meta_start_frame;
2212 seq::select_active_set(scene, strip_meta);
2213 if (seq::transform_test_overlap(scene, active_seqbase, strip_meta)) {
2214 seq::transform_seqbase_shuffle(active_seqbase, strip_meta, scene);
2215 }
2216
2220
2221 return OPERATOR_FINISHED;
2222}
2223
2225{
2226 /* Identifiers. */
2227 ot->name = "Make Meta Strip";
2228 ot->idname = "SEQUENCER_OT_meta_make";
2229 ot->description = "Group selected strips into a meta-strip";
2230
2231 /* API callbacks. */
2233 ot->poll = sequencer_edit_poll;
2234
2235 /* Flags. */
2236 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2237}
2238
2240
2241/* -------------------------------------------------------------------- */
2244
2246{
2247 Scene *scene = CTX_data_scene(C);
2248 Editing *ed = seq::editing_get(scene);
2249 Strip *active_strip = seq::select_active_get(scene);
2250
2251 if (active_strip == nullptr || active_strip->type != STRIP_TYPE_META) {
2252 return OPERATOR_CANCELLED;
2253 }
2254
2255 seq::prefetch_stop(scene);
2256
2257 LISTBASE_FOREACH (Strip *, strip, &active_strip->seqbase) {
2258 seq::relations_invalidate_cache(scene, strip);
2259 }
2260
2261 /* Remove all selected from meta, and put in main list.
2262 * Strip is moved within the same edit, no need to re-generate the UID. */
2263 BLI_movelisttolist(ed->seqbasep, &active_strip->seqbase);
2264 BLI_listbase_clear(&active_strip->seqbase);
2265
2266 ListBase *active_seqbase = seq::active_seqbase_get(ed);
2267 seq::edit_flag_for_removal(scene, active_seqbase, active_strip);
2268 seq::edit_remove_flagged_strips(scene, active_seqbase);
2269
2270 /* Test for effects and overlap. */
2271 LISTBASE_FOREACH (Strip *, strip, active_seqbase) {
2272 if (strip->flag & SELECT) {
2273 strip->flag &= ~SEQ_OVERLAP;
2274 if (seq::transform_test_overlap(scene, active_seqbase, strip)) {
2275 seq::transform_seqbase_shuffle(active_seqbase, strip, scene);
2276 }
2277 }
2278 }
2279
2282
2283 return OPERATOR_FINISHED;
2284}
2285
2287{
2288 /* Identifiers. */
2289 ot->name = "UnMeta Strip";
2290 ot->idname = "SEQUENCER_OT_meta_separate";
2291 ot->description = "Put the contents of a meta-strip back in the sequencer";
2292
2293 /* API callbacks. */
2295 ot->poll = sequencer_edit_poll;
2296
2297 /* Flags. */
2298 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2299}
2300
2302
2303/* -------------------------------------------------------------------- */
2306
2307static bool strip_jump_internal(Scene *scene,
2308 const short side,
2309 const bool do_skip_mute,
2310 const bool do_center)
2311{
2312 bool changed = false;
2313 int timeline_frame = scene->r.cfra;
2314 int next_frame = seq::time_find_next_prev_edit(
2315 scene, timeline_frame, side, do_skip_mute, do_center, false);
2316
2317 if (next_frame != timeline_frame) {
2318 scene->r.cfra = next_frame;
2319 changed = true;
2320 }
2321
2322 return changed;
2323}
2324
2326{
2327 /* Prevent changes during render. */
2328 if (G.is_rendering) {
2329 return false;
2330 }
2331
2332 return sequencer_edit_poll(C);
2333}
2334
2336{
2337 Scene *scene = CTX_data_scene(C);
2338 const bool next = RNA_boolean_get(op->ptr, "next");
2339 const bool center = RNA_boolean_get(op->ptr, "center");
2340
2341 /* Currently do_skip_mute is always true. */
2342 if (!strip_jump_internal(scene, next ? seq::SIDE_RIGHT : seq::SIDE_LEFT, true, center)) {
2343 return OPERATOR_CANCELLED;
2344 }
2345
2348
2349 return OPERATOR_FINISHED;
2350}
2351
2353{
2354 /* Identifiers. */
2355 ot->name = "Jump to Strip";
2356 ot->idname = "SEQUENCER_OT_strip_jump";
2357 ot->description = "Move frame to previous edit point";
2358
2359 /* API callbacks. */
2362
2363 /* Flags. */
2364 ot->flag = OPTYPE_UNDO;
2365
2366 /* Properties. */
2367 RNA_def_boolean(ot->srna, "next", true, "Next Strip", "");
2368 RNA_def_boolean(ot->srna, "center", true, "Use Strip Center", "");
2369}
2370
2372
2373/* -------------------------------------------------------------------- */
2376
2378 {seq::SIDE_LEFT, "LEFT", 0, "Left", ""},
2379 {seq::SIDE_RIGHT, "RIGHT", 0, "Right", ""},
2380 {0, nullptr, 0, nullptr, nullptr},
2381};
2382
2383static void swap_strips(Scene *scene, Strip *strip_a, Strip *strip_b)
2384{
2385 int gap = seq::time_left_handle_frame_get(scene, strip_b) -
2386 seq::time_right_handle_frame_get(scene, strip_a);
2387 int strip_a_start;
2388 int strip_b_start;
2389
2390 strip_b_start = (strip_b->start - seq::time_left_handle_frame_get(scene, strip_b)) +
2391 seq::time_left_handle_frame_get(scene, strip_a);
2392 seq::transform_translate_strip(scene, strip_b, strip_b_start - strip_b->start);
2393 seq::relations_invalidate_cache(scene, strip_b);
2394
2395 strip_a_start = (strip_a->start - seq::time_left_handle_frame_get(scene, strip_a)) +
2396 seq::time_right_handle_frame_get(scene, strip_b) + gap;
2397 seq::transform_translate_strip(scene, strip_a, strip_a_start - strip_a->start);
2398 seq::relations_invalidate_cache(scene, strip_a);
2399}
2400
2401static Strip *find_next_prev_strip(Scene *scene, Strip *test, int lr, int sel)
2402{
2403 /* sel: 0==unselected, 1==selected, -1==don't care. */
2404 Strip *strip, *best_strip = nullptr;
2405 Editing *ed = seq::editing_get(scene);
2406
2407 int dist, best_dist;
2408 best_dist = MAXFRAME * 2;
2409
2410 if (ed == nullptr) {
2411 return nullptr;
2412 }
2413
2414 strip = static_cast<Strip *>(ed->seqbasep->first);
2415 while (strip) {
2416 if ((strip != test) && (test->channel == strip->channel) &&
2417 ((sel == -1) || (sel == (strip->flag & SELECT))))
2418 {
2419 dist = MAXFRAME * 2;
2420
2421 switch (lr) {
2422 case seq::SIDE_LEFT:
2423 if (seq::time_right_handle_frame_get(scene, strip) <=
2425 {
2426 dist = seq::time_right_handle_frame_get(scene, test) -
2427 seq::time_left_handle_frame_get(scene, strip);
2428 }
2429 break;
2430 case seq::SIDE_RIGHT:
2431 if (seq::time_left_handle_frame_get(scene, strip) >=
2433 {
2434 dist = seq::time_left_handle_frame_get(scene, strip) -
2436 }
2437 break;
2438 }
2439
2440 if (dist == 0) {
2441 best_strip = strip;
2442 break;
2443 }
2444 if (dist < best_dist) {
2445 best_dist = dist;
2446 best_strip = strip;
2447 }
2448 }
2449 strip = static_cast<Strip *>(strip->next);
2450 }
2451 return best_strip; /* Can be nullptr. */
2452}
2453
2454static bool strip_is_parent(const Strip *par, const Strip *strip)
2455{
2456 return ((par->input1 == strip) || (par->input2 == strip));
2457}
2458
2460{
2461 Scene *scene = CTX_data_scene(C);
2462 Editing *ed = seq::editing_get(scene);
2463 Strip *active_strip = seq::select_active_get(scene);
2465 Strip *strip;
2466 int side = RNA_enum_get(op->ptr, "side");
2467
2468 if (active_strip == nullptr) {
2469 return OPERATOR_CANCELLED;
2470 }
2471
2472 strip = find_next_prev_strip(scene, active_strip, side, -1);
2473
2474 if (strip) {
2475
2476 /* Disallow effect strips. */
2477 if (seq::effect_get_num_inputs(strip->type) >= 1 &&
2478 (strip->effectdata || strip->input1 || strip->input2))
2479 {
2480 return OPERATOR_CANCELLED;
2481 }
2482 if ((seq::effect_get_num_inputs(active_strip->type) >= 1) &&
2483 (active_strip->effectdata || active_strip->input1 || active_strip->input2))
2484 {
2485 return OPERATOR_CANCELLED;
2486 }
2487
2489 if (seq::transform_is_locked(channels, strip) ||
2490 seq::transform_is_locked(channels, active_strip))
2491 {
2492 return OPERATOR_CANCELLED;
2493 }
2494
2495 switch (side) {
2496 case seq::SIDE_LEFT:
2497 swap_strips(scene, strip, active_strip);
2498 break;
2499 case seq::SIDE_RIGHT:
2500 swap_strips(scene, active_strip, strip);
2501 break;
2502 }
2503
2504 /* Do this in a new loop since both effects need to be calculated first. */
2505 LISTBASE_FOREACH (Strip *, istrip, seqbase) {
2506 if ((istrip->type & STRIP_TYPE_EFFECT) &&
2507 (strip_is_parent(istrip, active_strip) || strip_is_parent(istrip, strip)))
2508 {
2509 /* This may now overlap. */
2510 if (seq::transform_test_overlap(scene, seqbase, istrip)) {
2511 seq::transform_seqbase_shuffle(seqbase, istrip, scene);
2512 }
2513 }
2514 }
2515
2517 return OPERATOR_FINISHED;
2518 }
2519
2520 return OPERATOR_CANCELLED;
2521}
2522
2524{
2525 /* Identifiers. */
2526 ot->name = "Swap Strip";
2527 ot->idname = "SEQUENCER_OT_swap";
2528 ot->description = "Swap active strip with strip to the right or left";
2529
2530 /* API callbacks. */
2531 ot->exec = sequencer_swap_exec;
2532 ot->poll = sequencer_edit_poll;
2533
2534 /* Flags. */
2535 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2536
2537 /* Properties. */
2539 ot->srna, "side", prop_side_lr_types, seq::SIDE_RIGHT, "Side", "Side of the strip to swap");
2540}
2541
2543
2544/* -------------------------------------------------------------------- */
2547
2549{
2550 Scene *scene = CTX_data_scene(C);
2551 Strip *active_strip = seq::select_active_get(scene);
2552 StripElem *se = nullptr;
2553
2554 if (active_strip == nullptr || active_strip->data == nullptr) {
2555 return OPERATOR_CANCELLED;
2556 }
2557
2558 switch (active_strip->type) {
2559 case STRIP_TYPE_IMAGE:
2560 se = seq::render_give_stripelem(scene, active_strip, scene->r.cfra);
2561 break;
2562 case STRIP_TYPE_MOVIE:
2563 se = active_strip->data->stripdata;
2564 break;
2565 default:
2566 return OPERATOR_CANCELLED;
2567 }
2568
2569 if (se == nullptr) {
2570 return OPERATOR_CANCELLED;
2571 }
2572
2573 /* Prevent setting the render size if values aren't initialized. */
2574 if (se->orig_width <= 0 || se->orig_height <= 0) {
2575 return OPERATOR_CANCELLED;
2576 }
2577
2578 scene->r.xsch = se->orig_width;
2579 scene->r.ysch = se->orig_height;
2580
2581 active_strip->data->transform->scale_x = active_strip->data->transform->scale_y = 1.0f;
2582 active_strip->data->transform->xofs = active_strip->data->transform->yofs = 0.0f;
2583
2584 seq::relations_invalidate_cache(scene, active_strip);
2587
2588 return OPERATOR_FINISHED;
2589}
2590
2592{
2593 /* Identifiers. */
2594 ot->name = "Set Render Size";
2595 ot->idname = "SEQUENCER_OT_rendersize";
2596 ot->description = "Set render size and aspect from active strip";
2597
2598 /* API callbacks. */
2600 ot->poll = sequencer_edit_poll;
2601
2602 /* Flags. */
2603 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2604}
2605
2607
2608/* -------------------------------------------------------------------- */
2611
2613{
2614 /* Identifiers. */
2615 ot->name = "Copy";
2616 ot->idname = "SEQUENCER_OT_copy";
2617 ot->description = "Copy the selected strips to the internal clipboard";
2618
2619 /* API callbacks. */
2621 ot->poll = sequencer_edit_poll;
2622
2623 /* Flags. */
2624 ot->flag = OPTYPE_REGISTER;
2625}
2626
2628
2629/* -------------------------------------------------------------------- */
2632
2634{
2635 /* Identifiers. */
2636 ot->name = "Paste";
2637 ot->idname = "SEQUENCER_OT_paste";
2638 ot->description = "Paste strips from the internal clipboard";
2639
2640 /* API callbacks. */
2643
2644 /* Flags. */
2645 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2646
2647 /* Properties. */
2649 ot->srna,
2650 "keep_offset",
2651 false,
2652 "Keep Offset",
2653 "Keep strip offset relative to the current frame when pasting");
2655}
2656
2658
2659/* -------------------------------------------------------------------- */
2662
2664{
2665 Scene *scene = CTX_data_scene(C);
2666 Strip *strip_act;
2667 Strip *strip_other;
2668 const char *error_msg;
2669
2670 if (seq::select_active_get_pair(scene, &strip_act, &strip_other) == false) {
2671 BKE_report(op->reports, RPT_ERROR, "Please select two strips");
2672 return OPERATOR_CANCELLED;
2673 }
2674
2675 if (seq::edit_strip_swap(scene, strip_act, strip_other, &error_msg) == false) {
2676 BKE_report(op->reports, RPT_ERROR, error_msg);
2677 return OPERATOR_CANCELLED;
2678 }
2679
2680 if (strip_act->scene_sound) {
2681 BKE_sound_remove_scene_sound(scene, strip_act->scene_sound);
2682 }
2683
2684 if (strip_other->scene_sound) {
2685 BKE_sound_remove_scene_sound(scene, strip_other->scene_sound);
2686 }
2687
2688 strip_act->scene_sound = nullptr;
2689 strip_other->scene_sound = nullptr;
2690
2691 if (strip_act->sound) {
2692 BKE_sound_add_scene_sound_defaults(scene, strip_act);
2693 }
2694 if (strip_other->sound) {
2695 BKE_sound_add_scene_sound_defaults(scene, strip_other);
2696 }
2697
2698 seq::relations_invalidate_cache_raw(scene, strip_act);
2699 seq::relations_invalidate_cache_raw(scene, strip_other);
2700
2702
2703 return OPERATOR_FINISHED;
2704}
2705
2707{
2708 /* Identifiers. */
2709 ot->name = "Sequencer Swap Data";
2710 ot->idname = "SEQUENCER_OT_swap_data";
2711 ot->description = "Swap 2 sequencer strips";
2712
2713 /* API callbacks. */
2716
2717 /* Flags. */
2718 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2719}
2720
2722
2723/* -------------------------------------------------------------------- */
2726
2728 {STRIP_TYPE_CROSS, "CROSS", 0, "Crossfade", "Fade out of one video, fading into another"},
2729 {STRIP_TYPE_ADD, "ADD", 0, "Add", "Add together color channels from two videos"},
2730 {STRIP_TYPE_SUB, "SUBTRACT", 0, "Subtract", "Subtract one strip's color from another"},
2731 {STRIP_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", "Blend alpha on top of another video"},
2732 {STRIP_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", "Blend alpha below another video"},
2733 {STRIP_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Crossfade", "Crossfade with color correction"},
2734 {STRIP_TYPE_MUL, "MULTIPLY", 0, "Multiply", "Multiply color channels from two videos"},
2735 {STRIP_TYPE_WIPE, "WIPE", 0, "Wipe", "Sweep a transition line across the frame"},
2736 {STRIP_TYPE_GLOW, "GLOW", 0, "Glow", "Add blur and brightness to light areas"},
2737 {STRIP_TYPE_TRANSFORM, "TRANSFORM", 0, "Transform", "Apply scale, rotation, or translation"},
2738 {STRIP_TYPE_COLOR, "COLOR", 0, "Color", "Add a simple color strip"},
2739 {STRIP_TYPE_SPEED, "SPEED", 0, "Speed", "Timewarp video strips, modifying playback speed"},
2740 {STRIP_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", "Control active camera angles"},
2741 {STRIP_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", "Apply nondestructive effects"},
2742 {STRIP_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", "Soften details along axes"},
2743 {STRIP_TYPE_TEXT, "TEXT", 0, "Text", "Add a simple text strip"},
2744 {STRIP_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", "Combine two strips using blend modes"},
2745 {0, nullptr, 0, nullptr, nullptr},
2746};
2747
2749{
2750 Scene *scene = CTX_data_scene(C);
2751 Strip *strip = seq::select_active_get(scene);
2752 const int old_type = strip->type;
2753 const int new_type = RNA_enum_get(op->ptr, "type");
2754
2755 /* Free previous effect and init new effect. */
2757
2758 if ((strip->type & STRIP_TYPE_EFFECT) == 0) {
2759 return OPERATOR_CANCELLED;
2760 }
2761
2763 BKE_report(op->reports, RPT_ERROR, "New effect takes less or more inputs");
2764 return OPERATOR_CANCELLED;
2765 }
2766
2767 sh = seq::strip_effect_handle_get(strip);
2768 sh.free(strip, true);
2769
2770 strip->type = new_type;
2771
2772 /* If the strip's name is the default (equal to the old effect type),
2773 * rename to the new type to avoid confusion. */
2774 char name_base[MAX_ID_NAME];
2775 int name_num;
2776 BLI_string_split_name_number(strip->name + 2, '.', name_base, &name_num);
2777 if (STREQ(name_base, seq::get_default_stripname_by_type(old_type))) {
2778 seq::edit_strip_name_set(scene, strip, seq::strip_give_name(strip));
2779 seq::ensure_unique_name(strip, scene);
2780 }
2781
2782 sh = seq::strip_effect_handle_get(strip);
2783 sh.init(strip);
2784
2785 seq::relations_invalidate_cache(scene, strip);
2787
2788 return OPERATOR_FINISHED;
2789}
2790
2792{
2793 /* Identifiers. */
2794 ot->name = "Change Effect Type";
2795 ot->idname = "SEQUENCER_OT_change_effect_type";
2796 ot->description = "Replace effect strip with another that takes the same number of inputs";
2797
2798 /* API callbacks. */
2800 ot->poll = sequencer_effect_poll;
2801
2802 /* Flags. */
2803 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2804
2805 ot->prop = RNA_def_enum(ot->srna,
2806 "type",
2809 "Type",
2810 "Strip effect type");
2812}
2813
2815
2816/* -------------------------------------------------------------------- */
2819
2821{
2822 Main *bmain = CTX_data_main(C);
2823 Scene *scene = CTX_data_scene(C);
2824 Strip *strip = seq::select_active_get(scene);
2825 const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
2826 const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
2827 int minext_frameme, numdigits;
2828
2829 if (strip->type == STRIP_TYPE_IMAGE) {
2830 char directory[FILE_MAX];
2831 int len;
2832 StripElem *se;
2833
2834 /* Need to find min/max frame for placeholders. */
2835 if (use_placeholders) {
2836 len = sequencer_image_seq_get_minmax_frame(op, strip->sfra, &minext_frameme, &numdigits);
2837 }
2838 else {
2840 }
2841 if (len == 0) {
2842 return OPERATOR_CANCELLED;
2843 }
2844
2845 RNA_string_get(op->ptr, "directory", directory);
2846 if (is_relative_path) {
2847 /* TODO(@ideasman42): shouldn't this already be relative from the filesel?
2848 * (as the 'filepath' is) for now just make relative here,
2849 * but look into changing after 2.60. */
2850 BLI_path_rel(directory, BKE_main_blendfile_path(bmain));
2851 }
2852 STRNCPY(strip->data->dirpath, directory);
2853
2854 if (strip->data->stripdata) {
2855 MEM_freeN(strip->data->stripdata);
2856 }
2857 strip->data->stripdata = se = MEM_calloc_arrayN<StripElem>(len, "stripelem");
2858
2859 if (use_placeholders) {
2860 sequencer_image_seq_reserve_frames(op, se, len, minext_frameme, numdigits);
2861 }
2862 else {
2863 RNA_BEGIN (op->ptr, itemptr, "files") {
2864 char *filename = RNA_string_get_alloc(&itemptr, "name", nullptr, 0, nullptr);
2865 STRNCPY(se->filename, filename);
2866 MEM_freeN(filename);
2867 se++;
2868 }
2869 RNA_END;
2870 }
2871
2872 if (len == 1) {
2874 }
2875 else {
2877 }
2878
2879 /* Reset these else we won't see all the images. */
2880 strip->anim_startofs = strip->anim_endofs = 0;
2881
2882 /* Correct start/end frames so we don't move.
2883 * Important not to set strip->len = len; allow the function to handle it. */
2884 seq::add_reload_new_file(bmain, scene, strip, true);
2885 }
2886 else if (strip->type == STRIP_TYPE_SOUND_RAM) {
2887 bSound *sound = strip->sound;
2888 if (sound == nullptr) {
2889 return OPERATOR_CANCELLED;
2890 }
2891 char filepath[FILE_MAX];
2892 RNA_string_get(op->ptr, "filepath", filepath);
2893 STRNCPY(sound->filepath, filepath);
2894 BKE_sound_load(bmain, sound);
2895 }
2896 else {
2897 /* Lame, set rna filepath. */
2898 PropertyRNA *prop;
2899 char filepath[FILE_MAX];
2900
2901 PointerRNA strip_ptr = RNA_pointer_create_discrete(&scene->id, &RNA_Strip, strip);
2902
2903 RNA_string_get(op->ptr, "filepath", filepath);
2904 prop = RNA_struct_find_property(&strip_ptr, "filepath");
2905 RNA_property_string_set(&strip_ptr, prop, filepath);
2906 RNA_property_update(C, &strip_ptr, prop);
2908 }
2909
2912
2913 return OPERATOR_FINISHED;
2914}
2915
2917 wmOperator *op,
2918 const wmEvent * /*event*/)
2919{
2920 Scene *scene = CTX_data_scene(C);
2921 Strip *strip = seq::select_active_get(scene);
2922 char filepath[FILE_MAX];
2923
2925 filepath, sizeof(filepath), strip->data->dirpath, strip->data->stripdata->filename);
2926
2927 RNA_string_set(op->ptr, "directory", strip->data->dirpath);
2928 RNA_string_set(op->ptr, "filepath", filepath);
2929
2930 /* Set default display depending on strip type. */
2931 if (strip->type == STRIP_TYPE_IMAGE) {
2932 RNA_boolean_set(op->ptr, "filter_movie", false);
2933 }
2934 else {
2935 RNA_boolean_set(op->ptr, "filter_image", false);
2936 }
2937
2939
2941}
2942
2944{
2945 /* Identifiers. */
2946 ot->name = "Change Data/Files";
2947 ot->idname = "SEQUENCER_OT_change_path";
2948
2949 /* API callbacks. */
2953
2954 /* Flags. */
2955 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2956
2965 RNA_def_boolean(ot->srna,
2966 "use_placeholders",
2967 false,
2968 "Use Placeholders",
2969 "Use placeholders for missing frames of the strip");
2970}
2971
2973
2974/* -------------------------------------------------------------------- */
2977
2979{
2981 if (ed == nullptr) {
2982 return false;
2983 }
2984 Strip *strip = ed->act_strip;
2985 return ((strip != nullptr) && (strip->type == STRIP_TYPE_SCENE));
2986}
2988{
2989 Main *bmain = CTX_data_main(C);
2990 Scene *scene = CTX_data_scene(C);
2991 Scene *scene_seq = static_cast<Scene *>(
2992 BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene")));
2993
2994 if (scene_seq == nullptr) {
2995 BKE_report(op->reports, RPT_ERROR, "Scene not found");
2996 return OPERATOR_CANCELLED;
2997 }
2998
2999 /* Assign new scene. */
3000 Strip *strip = seq::select_active_get(scene);
3001 if (strip) {
3002 strip->scene = scene_seq;
3003 /* Do a refresh of the sequencer data. */
3007 }
3008
3011
3012 return OPERATOR_FINISHED;
3013}
3014
3016 wmOperator *op,
3017 const wmEvent *event)
3018{
3019 if (!RNA_struct_property_is_set(op->ptr, "scene")) {
3020 return WM_enum_search_invoke(C, op, event);
3021 }
3022
3023 return sequencer_change_scene_exec(C, op);
3024}
3025
3027{
3028 PropertyRNA *prop;
3029
3030 /* Identifiers. */
3031 ot->name = "Change Scene";
3032 ot->idname = "SEQUENCER_OT_change_scene";
3033 ot->description = "Change Scene assigned to Strip";
3034
3035 /* API callbacks. */
3039
3040 /* Flags. */
3041 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3042
3043 /* Properties. */
3044 prop = RNA_def_enum(ot->srna, "scene", rna_enum_dummy_NULL_items, 0, "Scene", "");
3047 ot->prop = prop;
3048}
3049
3051
3052/* -------------------------------------------------------------------- */
3055
3057static int strip_cmp_time_startdisp_channel(void *thunk, const void *a, const void *b)
3058{
3059 const Scene *scene = static_cast<Scene *>(thunk);
3060 const Strip *strip_a = static_cast<const Strip *>(a);
3061 const Strip *strip_b = static_cast<const Strip *>(b);
3062
3063 int strip_a_start = seq::time_left_handle_frame_get(scene, strip_a);
3064 int strip_b_start = seq::time_left_handle_frame_get(scene, strip_b);
3065
3066 /* If strips have the same start frame favor the one with a higher channel. */
3067 if (strip_a_start == strip_b_start) {
3068 return strip_a->channel > strip_b->channel;
3069 }
3070
3071 return (strip_a_start > strip_b_start);
3072}
3073
3075 wmOperator *op,
3076 const wmEvent * /*event*/)
3077{
3079
3081
3083}
3084
3089
3090static bool strip_get_text_strip_cb(Strip *strip, void *user_data)
3091{
3092 Seq_get_text_cb_data *cd = (Seq_get_text_cb_data *)user_data;
3095 /* Only text strips that are not muted and don't end with negative frame. */
3096 if ((strip->type == STRIP_TYPE_TEXT) && !seq::render_is_muted(channels, strip) &&
3097 (seq::time_right_handle_frame_get(cd->scene, strip) > cd->scene->r.sfra))
3098 {
3099 BLI_addtail(cd->text_seq, MEM_dupallocN(strip));
3100 }
3101 return true;
3102}
3103
3105{
3106 Scene *scene = CTX_data_scene(C);
3107 Strip *strip, *strip_next;
3108 Editing *ed = seq::editing_get(scene);
3109 ListBase text_seq = {nullptr};
3110 int iter = 1; /* Sequence numbers in `.srt` files are 1-indexed. */
3111 FILE *file;
3112 char filepath[FILE_MAX];
3113
3114 if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
3115 BKE_report(op->reports, RPT_ERROR, "No filepath given");
3116 return OPERATOR_CANCELLED;
3117 }
3118
3119 RNA_string_get(op->ptr, "filepath", filepath);
3120 BLI_path_extension_ensure(filepath, sizeof(filepath), ".srt");
3121
3122 /* Avoid File write exceptions. */
3123 if (!BLI_exists(filepath)) {
3125 if (!BLI_file_touch(filepath)) {
3126 BKE_report(op->reports, RPT_ERROR, "Can't create subtitle file");
3127 return OPERATOR_CANCELLED;
3128 }
3129 }
3130 else if (!BLI_file_is_writable(filepath)) {
3131 BKE_report(op->reports, RPT_ERROR, "Can't overwrite export file");
3132 return OPERATOR_CANCELLED;
3133 }
3134
3135 if (ed != nullptr) {
3136 Seq_get_text_cb_data cb_data = {&text_seq, scene};
3138 }
3139
3140 if (BLI_listbase_is_empty(&text_seq)) {
3141 BKE_report(op->reports, RPT_ERROR, "No subtitles (text strips) to export");
3142 return OPERATOR_CANCELLED;
3143 }
3144
3146
3147 /* Open and write file. */
3148 file = BLI_fopen(filepath, "w");
3149
3150 for (strip = static_cast<Strip *>(text_seq.first); strip; strip = strip_next) {
3151 TextVars *data = static_cast<TextVars *>(strip->effectdata);
3152 char timecode_str_start[32];
3153 char timecode_str_end[32];
3154
3155 /* Write time-code relative to start frame of scene. Don't allow negative time-codes. */
3157 timecode_str_start,
3158 sizeof(timecode_str_start),
3159 -2,
3160 FRA2TIME(max_ii(seq::time_left_handle_frame_get(scene, strip) - scene->r.sfra, 0)),
3161 FPS,
3164 timecode_str_end,
3165 sizeof(timecode_str_end),
3166 -2,
3167 FRA2TIME(seq::time_right_handle_frame_get(scene, strip) - scene->r.sfra),
3168 FPS,
3170
3171 fprintf(
3172 file, "%d\n%s --> %s\n%s\n\n", iter++, timecode_str_start, timecode_str_end, data->text);
3173
3174 strip_next = static_cast<Strip *>(strip->next);
3175 MEM_freeN(strip);
3176 }
3177
3178 fclose(file);
3179
3180 return OPERATOR_FINISHED;
3181}
3182
3184{
3185 Editing *ed;
3186 Strip *strip;
3187 return (((ed = seq::editing_get(CTX_data_scene(C))) != nullptr) &&
3188 ((strip = ed->act_strip) != nullptr) && (strip->type == STRIP_TYPE_TEXT));
3189}
3190
3192{
3193 /* Identifiers. */
3194 ot->name = "Export Subtitles";
3195 ot->idname = "SEQUENCER_OT_export_subtitles";
3196 ot->description = "Export .srt file containing text strips";
3197
3198 /* API callbacks. */
3202
3203 /* Flags. */
3204 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3205
3209 FILE_SAVE,
3213}
3214
3216
3217/* -------------------------------------------------------------------- */
3220
3222{
3223 Scene *scene = CTX_data_scene(C);
3224 Editing *ed = seq::editing_get(scene);
3225
3226 int sfra = MAXFRAME;
3227 int efra = -MAXFRAME;
3228 bool selected = false;
3229 const bool preview = RNA_boolean_get(op->ptr, "preview");
3230
3231 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
3232 if (strip->flag & SELECT) {
3233 selected = true;
3234 sfra = min_ii(sfra, seq::time_left_handle_frame_get(scene, strip));
3235 /* Offset of -1 is needed because in the sequencer every frame has width.
3236 * Range from 1 to 1 is drawn as range 1 to 2, because 1 frame long strip starts at frame 1
3237 * and ends at frame 2. See #106480. */
3238 efra = max_ii(efra, seq::time_right_handle_frame_get(scene, strip) - 1);
3239 }
3240 }
3241
3242 if (!selected) {
3243 BKE_report(op->reports, RPT_WARNING, "Select one or more strips");
3244 return OPERATOR_CANCELLED;
3245 }
3246 if (efra < 0) {
3247 BKE_report(op->reports, RPT_ERROR, "Can't set a negative range");
3248 return OPERATOR_CANCELLED;
3249 }
3250
3251 if (preview) {
3252 scene->r.flag |= SCER_PRV_RANGE;
3253 scene->r.psfra = max_ii(0, sfra);
3254 scene->r.pefra = efra;
3255 }
3256 else {
3257 scene->r.flag &= ~SCER_PRV_RANGE;
3258 scene->r.sfra = max_ii(0, sfra);
3259 scene->r.efra = efra;
3260 }
3261
3263
3264 return OPERATOR_FINISHED;
3265}
3266
3268{
3269 PropertyRNA *prop;
3270
3271 /* Identifiers. */
3272 ot->name = "Set Range to Strips";
3273 ot->idname = "SEQUENCER_OT_set_range_to_strips";
3274 ot->description = "Set the frame range to the selected strips start and end";
3275
3276 /* API callbacks. */
3278 ot->poll = sequencer_edit_poll;
3279
3280 /* Flags. */
3281 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3282
3283 prop = RNA_def_boolean(ot->srna, "preview", false, "Preview", "Set the preview range instead");
3285}
3286
3288
3289/* -------------------------------------------------------------------- */
3292
3293enum {
3298};
3299
3301 {STRIP_TRANSFORM_POSITION, "POSITION", 0, "Position", "Reset strip transform location"},
3302 {STRIP_TRANSFORM_SCALE, "SCALE", 0, "Scale", "Reset strip transform scale"},
3303 {STRIP_TRANSFORM_ROTATION, "ROTATION", 0, "Rotation", "Reset strip transform rotation"},
3304 {STRIP_TRANSFORM_ALL, "ALL", 0, "All", "Reset strip transform location, scale and rotation"},
3305 {0, nullptr, 0, nullptr, nullptr},
3306};
3307
3309{
3310 Scene *scene = CTX_data_scene(C);
3311 const Editing *ed = seq::editing_get(scene);
3312 const int property = RNA_enum_get(op->ptr, "property");
3313
3314 const bool use_autokeyframe = blender::animrig::is_autokey_on(scene);
3315 const bool only_when_keyed = blender::animrig::is_keying_flag(scene,
3317
3318 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
3319 if (strip->flag & SELECT && strip->type != STRIP_TYPE_SOUND_RAM) {
3320 StripTransform *transform = strip->data->transform;
3321 PropertyRNA *prop;
3322 PointerRNA ptr = RNA_pointer_create_discrete(&scene->id, &RNA_StripTransform, transform);
3323 switch (property) {
3325 transform->xofs = 0;
3326 transform->yofs = 0;
3327 if (use_autokeyframe) {
3328 prop = RNA_struct_find_property(&ptr, "offset_x");
3330 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3331 prop = RNA_struct_find_property(&ptr, "offset_y");
3333 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3334 }
3335 break;
3337 transform->scale_x = 1.0f;
3338 transform->scale_y = 1.0f;
3339 if (use_autokeyframe) {
3340 prop = RNA_struct_find_property(&ptr, "scale_x");
3342 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3343 prop = RNA_struct_find_property(&ptr, "scale_y");
3345 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3346 }
3347 break;
3349 transform->rotation = 0.0f;
3350 if (use_autokeyframe) {
3351 prop = RNA_struct_find_property(&ptr, "rotation");
3353 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3354 }
3355 break;
3357 transform->xofs = 0;
3358 transform->yofs = 0;
3359 transform->scale_x = 1.0f;
3360 transform->scale_y = 1.0f;
3361 transform->rotation = 0.0f;
3362 if (use_autokeyframe) {
3363 prop = RNA_struct_find_property(&ptr, "offset_x");
3365 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3366 prop = RNA_struct_find_property(&ptr, "offset_y");
3368 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3369 prop = RNA_struct_find_property(&ptr, "scale_x");
3371 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3372 prop = RNA_struct_find_property(&ptr, "scale_y");
3374 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3375 prop = RNA_struct_find_property(&ptr, "rotation");
3377 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3378 }
3379 break;
3380 }
3381 seq::relations_invalidate_cache(scene, strip);
3382 }
3383 }
3384
3386 return OPERATOR_FINISHED;
3387}
3388
3390{
3391 /* Identifiers. */
3392 ot->name = "Clear Strip Transform";
3393 ot->idname = "SEQUENCER_OT_strip_transform_clear";
3394 ot->description = "Reset image transformation to default value";
3395
3396 /* API callbacks. */
3398 ot->poll = sequencer_edit_poll;
3399
3400 /* Flags. */
3401 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3402
3403 ot->prop = RNA_def_enum(ot->srna,
3404 "property",
3407 "Property",
3408 "Strip transform property to be reset");
3409}
3410
3412
3413/* -------------------------------------------------------------------- */
3416
3418 {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image so fits in preview"},
3419 {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image so it fills preview completely"},
3420 {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image so it fills preview"},
3421 {0, nullptr, 0, nullptr, nullptr},
3422};
3423
3425{
3426 Scene *scene = CTX_data_scene(C);
3427 const Editing *ed = seq::editing_get(scene);
3428 const eSeqImageFitMethod fit_method = eSeqImageFitMethod(RNA_enum_get(op->ptr, "fit_method"));
3429
3430 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
3431 if (strip->flag & SELECT && strip->type != STRIP_TYPE_SOUND_RAM) {
3432 const int timeline_frame = scene->r.cfra;
3433 StripElem *strip_elem = seq::render_give_stripelem(scene, strip, timeline_frame);
3434
3435 if (strip_elem == nullptr) {
3436 continue;
3437 }
3438
3440 strip_elem->orig_width,
3441 strip_elem->orig_height,
3442 scene->r.xsch,
3443 scene->r.ysch,
3444 fit_method);
3445 seq::relations_invalidate_cache(scene, strip);
3446 }
3447 }
3448
3450 return OPERATOR_FINISHED;
3451}
3452
3454{
3455 /* Identifiers. */
3456 ot->name = "Strip Transform Set Fit";
3457 ot->idname = "SEQUENCER_OT_strip_transform_fit";
3458
3459 /* API callbacks. */
3461 ot->poll = sequencer_edit_poll;
3462
3463 /* Flags. */
3464 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3465
3466 ot->prop = RNA_def_enum(ot->srna,
3467 "fit_method",
3470 "Fit Method",
3471 "Scale fit fit_method");
3472}
3473
3475{
3476 Scene *scene = CTX_data_scene(C);
3477 const Editing *ed = seq::editing_get(scene);
3478 const short color_tag = RNA_enum_get(op->ptr, "color");
3479
3480 LISTBASE_FOREACH (Strip *, strip, ed->seqbasep) {
3481 if (strip->flag & SELECT) {
3482 strip->color_tag = color_tag;
3483 }
3484 }
3485
3487 return OPERATOR_FINISHED;
3488}
3489
3491{
3492 Scene *scene = CTX_data_scene(C);
3493 if (scene == nullptr) {
3494 return false;
3495 }
3496
3497 Editing *ed = seq::editing_get(scene);
3498 if (ed == nullptr) {
3499 return false;
3500 }
3501
3502 Strip *act_strip = ed->act_strip;
3503 return act_strip != nullptr;
3504}
3505
3507{
3508 /* Identifiers. */
3509 ot->name = "Set Color Tag";
3510 ot->idname = "SEQUENCER_OT_strip_color_tag_set";
3511 ot->description = "Set a color tag for the selected strips";
3512
3513 /* API callbacks. */
3516
3517 /* Flags. */
3518 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3519
3520 RNA_def_enum(ot->srna, "color", rna_enum_strip_color_items, STRIP_COLOR_NONE, "Color Tag", "");
3521}
3522
3524
3525/* -------------------------------------------------------------------- */
3528
3530{
3531 Scene *scene = CTX_data_scene(C);
3532 SpaceSeq *sseq = CTX_wm_space_seq(C);
3533
3534 float cursor_pixel[2];
3535 RNA_float_get_array(op->ptr, "location", cursor_pixel);
3536
3537 blender::float2 cursor_region = seq::image_preview_unit_from_px(scene, cursor_pixel);
3538 copy_v2_v2(sseq->cursor, cursor_region);
3539
3541
3542 /* Use pass-through to allow click-drag to transform the cursor. */
3544}
3545
3547 wmOperator *op,
3548 const wmEvent *event)
3549{
3550 ARegion *region = CTX_wm_region(C);
3551 float cursor_pixel[2];
3553 &region->v2d, event->mval[0], event->mval[1], &cursor_pixel[0], &cursor_pixel[1]);
3554
3555 RNA_float_set_array(op->ptr, "location", cursor_pixel);
3556
3557 return sequencer_set_2d_cursor_exec(C, op);
3558}
3559
3561{
3562 /* identifiers */
3563 ot->name = "Set 2D Cursor";
3564 ot->description = "Set 2D cursor location";
3565 ot->idname = "SEQUENCER_OT_cursor_set";
3566
3567 /* API callbacks. */
3571
3572 /* flags */
3573 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3574
3575 /* properties */
3577 "location",
3578 2,
3579 nullptr,
3580 -FLT_MAX,
3581 FLT_MAX,
3582 "Location",
3583 "Cursor location in normalized preview coordinates",
3584 -10.0f,
3585 10.0f);
3586}
3587
3589
3590/* -------------------------------------------------------------------- */
3593
3595{
3596 Scene *scene = CTX_data_scene(C);
3597 Editing *ed = seq::editing_get(scene);
3598 Strip *strip = ed->act_strip;
3599
3600 const int old_start = seq::time_left_handle_frame_get(scene, strip);
3601 const int old_end = seq::time_right_handle_frame_get(scene, strip);
3602
3603 Scene *target_scene = strip->scene;
3604
3605 strip->len = target_scene->r.efra - target_scene->r.sfra + 1;
3606 seq::time_left_handle_frame_set(scene, strip, old_start);
3607 seq::time_right_handle_frame_set(scene, strip, old_end);
3608
3612 return OPERATOR_FINISHED;
3613}
3614
3616{
3618 return (ed != nullptr && ed->act_strip != nullptr && ed->act_strip->type == STRIP_TYPE_SCENE);
3619}
3620
3622{
3623 /* identifiers */
3624 ot->name = "Update Scene Frame Range";
3625 ot->description = "Update frame range of scene strip";
3626 ot->idname = "SEQUENCER_OT_scene_frame_range_update";
3627
3628 /* API callbacks. */
3631
3632 /* flags */
3633 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3634}
3635
3637
3638} // namespace blender::ed::vse
Functions for backward compatibility with the legacy Action API.
ScrArea * CTX_wm_area(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
SpaceSeq * CTX_wm_space_seq(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:872
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
void * BKE_sound_add_scene_sound_defaults(struct Scene *scene, struct Strip *sequence)
void BKE_sound_load(struct Main *bmain, struct bSound *sound)
void BKE_sound_remove_scene_sound(struct Scene *scene, void *handle)
File and directory operations.
bool BLI_file_touch(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:316
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:373
bool BLI_file_is_writable(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition fileops_c.cc:291
FILE * BLI_fopen(const char *filepath, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:429
void * BLI_findlink(const ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:534
void void void BLI_movelisttolist(ListBase *dst, ListBase *src) ATTR_NONNULL(1
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(ListBase *lb)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void void void BLI_listbase_sort_r(ListBase *listbase, int(*cmp)(void *, const void *, const void *), void *thunk) ATTR_NONNULL(1
MINLINE int round_fl_to_int(float a)
MINLINE int min_ii(int a, int b)
MINLINE int max_ii(int a, int b)
MINLINE void copy_v2_v2(float r[2], const float a[2])
#define FILE_MAX
#define BLI_path_join(...)
bool BLI_path_extension_ensure(char *path, size_t path_maxncpy, const char *ext) ATTR_NONNULL(1
bool void BLI_path_rel(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1)
int bool BLI_str_startswith(const char *__restrict str, const char *__restrict start) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
int bool bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(1
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
size_t BLI_timecode_string_from_time(char *str, size_t maxncpy, int brevity_level, float time_seconds, double fps, short timecode_style) ATTR_NONNULL()
Definition timecode.cc:22
#define ELEM(...)
#define STREQ(a, b)
#define BLT_I18NCONTEXT_ID_SEQUENCE
#define TIP_(msgid)
#define IFACE_(msgid)
#define DATA_(msgid)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_FRAME_CHANGE
Definition DNA_ID.h:1033
@ ID_RECALC_AUDIO
Definition DNA_ID.h:1040
@ ID_RECALC_SEQUENCER_STRIPS
Definition DNA_ID.h:1030
@ ID_RECALC_ANIMATION_NO_FLUSH
Definition DNA_ID.h:1084
eSeqImageFitMethod
@ SEQ_SCALE_TO_FILL
@ SEQ_STRETCH_TO_FILL
@ SEQ_SCALE_TO_FIT
#define MINFRAME
@ SCER_PRV_RANGE
#define FPS
#define FRA2TIME(a)
#define MAXFRAME
@ RGN_TYPE_CHANNELS
@ RGN_TYPE_WINDOW
@ RGN_TYPE_PREVIEW
@ STRIP_TYPE_GAUSSIAN_BLUR
@ STRIP_TYPE_GAMCROSS
@ STRIP_TYPE_SCENE
@ STRIP_TYPE_COLORMIX
@ STRIP_TYPE_WIPE
@ STRIP_TYPE_TEXT
@ STRIP_TYPE_SOUND_RAM
@ STRIP_TYPE_ADD
@ STRIP_TYPE_TRANSFORM
@ STRIP_TYPE_IMAGE
@ STRIP_TYPE_MOVIE
@ STRIP_TYPE_GLOW
@ STRIP_TYPE_SUB
@ STRIP_TYPE_MUL
@ STRIP_TYPE_SPEED
@ STRIP_TYPE_EFFECT
@ STRIP_TYPE_COLOR
@ STRIP_TYPE_ADJUSTMENT
@ STRIP_TYPE_META
@ STRIP_TYPE_MULTICAM
@ STRIP_TYPE_ALPHAUNDER
@ STRIP_TYPE_CROSS
@ STRIP_TYPE_ALPHAOVER
@ STRIP_COLOR_NONE
#define STRIP_ALLSEL
@ SEQ_SHOW_OFFSETS
@ SEQ_SINGLE_FRAME_CONTENT
@ SEQ_RIGHTSEL
@ SEQ_IGNORE_CHANNEL_LOCK
@ SEQ_OVERLAP
@ SEQ_LEFTSEL
#define STRIP_HAS_PATH(_strip)
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_BLENDER
@ FILE_TYPE_FOLDER
@ SEQ_VIEW_SEQUENCE_PREVIEW
@ SEQ_VIEW_SEQUENCE
@ SEQ_VIEW_PREVIEW
@ FILE_DEFAULTDISPLAY
@ SEQ_DRAW_IMG_IMBUF
@ AUTOKEY_FLAG_INSERTAVAILABLE
@ USER_TIMECODE_SUBRIP
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
void ED_fileselect_ensure_default_filepath(bContext *C, wmOperator *op, const char *extension)
Definition filesel.cc:1490
void initNumInput(NumInput *n)
Definition numinput.cc:69
#define NUM_STR_REP_LEN
bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
Definition numinput.cc:311
bool applyNumInput(NumInput *n, float *vec)
Definition numinput.cc:189
void outputNumInput(NumInput *n, char *str, const UnitSettings &unit_settings)
Definition numinput.cc:87
bool hasNumInput(const NumInput *n)
Definition numinput.cc:170
bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene) ATTR_NONNULL()
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:872
bool ED_operator_sequencer_active(bContext *C)
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:1040
Read Guarded memory(de)allocation.
#define RNA_BEGIN(sptr, itemptr, propname)
#define RNA_END
const EnumPropertyItem * RNA_scene_without_active_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:406
@ PROP_SKIP_SAVE
Definition RNA_types.hh:330
@ PROP_HIDDEN
Definition RNA_types.hh:324
#define C
Definition RandGen.cpp:29
#define STRIP_DUPE_UNIQUE_NAME
@ UI_ITEM_R_EXPAND
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
#define UI_ITEM_NONE
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
#define UI_MAX_DRAW_STR
View2D * UI_view2d_fromcontext(const bContext *C)
Definition view2d.cc:1854
void UI_view2d_region_to_view(const View2D *v2d, float x, float y, float *r_view_x, float *r_view_y) ATTR_NONNULL()
Definition view2d.cc:1667
float UI_view2d_scale_get_x(const View2D *v2d)
Definition view2d.cc:1920
@ WM_FILESEL_FILES
Definition WM_api.hh:1076
@ WM_FILESEL_DIRECTORY
Definition WM_api.hh:1073
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1072
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1075
@ FILE_OPENFILE
Definition WM_api.hh:1084
@ FILE_SAVE
Definition WM_api.hh:1085
#define ND_SEQUENCER
Definition WM_types.hh:434
#define ND_SPACE_SEQUENCER
Definition WM_types.hh:532
#define ND_RENDER_OPTIONS
Definition WM_types.hh:432
@ OPTYPE_BLOCKING
Definition WM_types.hh:184
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
@ OPTYPE_GRAB_CURSOR_X
Definition WM_types.hh:190
#define NC_SCENE
Definition WM_types.hh:375
#define ND_FRAME_RANGE
Definition WM_types.hh:448
#define ND_FRAME
Definition WM_types.hh:431
#define NA_REMOVED
Definition WM_types.hh:584
#define ND_SCENEBROWSE
Definition WM_types.hh:429
#define ND_ANIMCHAN
Definition WM_types.hh:493
@ KM_PRESS
Definition WM_types.hh:308
#define NC_SPACE
Definition WM_types.hh:389
blender::StringRef BLI_string_split_name_number(const blender::StringRef name_full, const char delim, int &r_number)
BMesh const char void * data
long long int int64_t
void item(std::string text, int icon1, int icon2=0)
Definition area.cc:979
void opmodal(std::string text, const wmOperatorType *ot, int propvalue, bool inverted=false)
Definition area.cc:1005
constexpr bool is_empty() const
constexpr const char * data() const
void add_multiple(Span< Key > keys)
int64_t size() const
int64_t remove_if(Predicate &&predicate)
#define SELECT
IMETHOD Vector diff(const Vector &a, const Vector &b, double dt)
Definition frames.inl:1166
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
#define MAX_ID_NAME
#define ID_IS_EDITABLE(_id)
#define MEM_reallocN(vmemh, len)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_dupallocN(const void *vmemh)
Definition mallocn.cc:143
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong * next
#define G(x, y, z)
Vector< FCurve * > fcurves_for_assigned_action(AnimData *adt)
bool is_autokey_on(const Scene *scene)
bool autokeyframe_property(bContext *C, Scene *scene, PointerRNA *ptr, PropertyRNA *prop, int rnaindex, float cfra, bool only_if_property_keyed)
bool is_keying_flag(const Scene *scene, eKeying_Flag flag)
static wmOperatorStatus sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus sequencer_unmute_exec(bContext *C, wmOperator *op)
static float slip_apply_clamp(const Scene *scene, const SlipData *data, float *r_offset)
void SEQUENCER_OT_meta_toggle(wmOperatorType *ot)
static void slip_update_header(const Scene *scene, ScrArea *area, SlipData *data, const float offset)
bool sequencer_edit_poll(bContext *C)
void SEQUENCER_OT_meta_make(wmOperatorType *ot)
static void sequencer_split_ui(bContext *, wmOperator *op)
static wmOperatorStatus sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
static int sequence_split_side_for_exec_get(wmOperator *op)
void SEQUENCER_OT_images_separate(wmOperatorType *ot)
void SEQUENCER_OT_snap(wmOperatorType *ot)
static bool sequencer_strip_change_scene_poll(bContext *C)
void SEQUENCER_OT_swap_inputs(wmOperatorType *ot)
static wmOperatorStatus sequencer_split_exec(bContext *C, wmOperator *op)
static wmOperatorStatus sequencer_add_duplicate_exec(bContext *C, wmOperator *)
static wmOperatorStatus sequencer_export_subtitles_invoke(bContext *C, wmOperator *op, const wmEvent *)
static wmOperatorStatus sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void SEQUENCER_OT_offset_clear(wmOperatorType *ot)
static void slip_strips_delta(wmOperator *op, Scene *scene, SlipData *data, const float delta)
static void sequencer_delete_strip_data(bContext *C, Strip *strip)
static void slip_cleanup(bContext *C, wmOperator *op, Scene *scene)
bool has_playback_animation(const Scene *scene)
bool check_show_strip(const SpaceSeq &sseq)
void SEQUENCER_OT_copy(wmOperatorType *ot)
static wmOperatorStatus sequencer_mute_exec(bContext *C, wmOperator *op)
static wmOperatorStatus sequencer_separate_images_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void sequencer_image_seq_reserve_frames(wmOperator *op, StripElem *se, int len, int minframe, int numdigits)
wmOperatorStatus sequencer_clipboard_copy_exec(bContext *C, wmOperator *op)
static wmOperatorStatus sequencer_gap_insert_exec(bContext *C, wmOperator *op)
static wmOperatorStatus sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *)
void SEQUENCER_OT_gap_remove(wmOperatorType *ot)
void SEQUENCER_OT_gap_insert(wmOperatorType *ot)
static wmOperatorStatus sequencer_separate_images_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_change_scene(wmOperatorType *ot)
static wmOperatorStatus sequencer_swap_inputs_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_refresh_all(wmOperatorType *ot)
static wmOperatorStatus sequencer_change_path_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem scale_fit_methods[]
blender::VectorSet< Strip * > all_strips_from_context(bContext *C)
static const EnumPropertyItem transform_reset_properties[]
static wmOperatorStatus sequencer_reload_exec(bContext *C, wmOperator *op)
static bool sequencer_strip_is_text_poll(bContext *C)
blender::VectorSet< Strip * > selected_strips_from_context(bContext *C)
void SEQUENCER_OT_strip_transform_clear(wmOperatorType *ot)
static wmOperatorStatus sequencer_snap_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_lock(wmOperatorType *ot)
static wmOperatorStatus sequencer_delete_exec(bContext *C, wmOperator *op)
const EnumPropertyItem sequencer_prop_effect_types[]
static wmOperatorStatus sequencer_set_2d_cursor_exec(bContext *C, wmOperator *op)
static wmOperatorStatus sequencer_set_2d_cursor_invoke(bContext *C, wmOperator *op, const wmEvent *event)
void SEQUENCER_OT_mute(wmOperatorType *ot)
static wmOperatorStatus sequencer_change_scene_exec(bContext *C, wmOperator *op)
static const EnumPropertyItem prop_side_lr_types[]
static wmOperatorStatus sequencer_refresh_all_exec(bContext *C, wmOperator *)
bool maskedit_poll(bContext *C)
bool sequencer_editing_initialized_and_active(bContext *C)
static wmOperatorStatus sequencer_gap_remove_exec(bContext *C, wmOperator *op)
static bool sequencer_fcurves_targets_color_strip(const FCurve *fcurve)
static bool strip_get_text_strip_cb(Strip *strip, void *user_data)
static wmOperatorStatus sequencer_slip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus sequencer_change_path_invoke(bContext *C, wmOperator *op, const wmEvent *)
void SEQUENCER_OT_strip_color_tag_set(wmOperatorType *ot)
StringRef effect_inputs_validate(const VectorSet< Strip * > &inputs, int num_inputs)
void SEQUENCER_OT_slip(wmOperatorType *ot)
static wmOperatorStatus sequencer_disconnect_exec(bContext *C, wmOperator *)
void SEQUENCER_OT_unmute(wmOperatorType *ot)
static Strip * find_next_prev_strip(Scene *scene, Strip *test, int lr, int sel)
VectorSet< Strip * > strip_effect_get_new_inputs(const Scene *scene, int num_inputs, bool ignore_active)
static wmOperatorStatus sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_connect(wmOperatorType *ot)
static int strip_cmp_time_startdisp_channel(void *thunk, const void *a, const void *b)
static wmOperatorStatus sequencer_strip_transform_fit_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_change_effect_type(wmOperatorType *ot)
void SEQUENCER_OT_paste(wmOperatorType *ot)
bool sequencer_edit_with_channel_region_poll(bContext *C)
Strip * strip_under_mouse_get(const Scene *scene, const View2D *v2d, const int mval[2])
static wmOperatorStatus sequencer_meta_separate_exec(bContext *C, wmOperator *)
void SEQUENCER_OT_rendersize(wmOperatorType *ot)
void SEQUENCER_OT_scene_frame_range_update(wmOperatorType *ot)
void sequencer_select_do_updates(const bContext *C, Scene *scene)
void SEQUENCER_OT_reload(wmOperatorType *ot)
void SEQUENCER_OT_strip_transform_fit(wmOperatorType *ot)
bool sequencer_view_preview_only_poll(const bContext *C)
bool sequencer_strip_editable_poll(bContext *C)
void SEQUENCER_OT_change_path(wmOperatorType *ot)
static wmOperatorStatus sequencer_rendersize_exec(bContext *C, wmOperator *)
static wmOperatorStatus sequencer_strip_jump_exec(bContext *C, wmOperator *op)
static void swap_strips(Scene *scene, Strip *strip_a, Strip *strip_b)
bool maskedit_mask_poll(bContext *C)
static wmOperatorStatus sequencer_offset_clear_exec(bContext *C, wmOperator *)
static wmOperatorStatus sequencer_connect_exec(bContext *C, wmOperator *op)
static wmOperatorStatus sequencer_meta_make_exec(bContext *C, wmOperator *)
static int mouse_frame_side(View2D *v2d, short mouse_x, int frame)
static void slip_draw_status(bContext *C, const wmOperator *op)
void SEQUENCER_OT_set_range_to_strips(wmOperatorType *ot)
void SEQUENCER_OT_reassign_inputs(wmOperatorType *ot)
void SEQUENCER_OT_unlock(wmOperatorType *ot)
bool deselect_all_strips(const Scene *scene)
static bool sequencer_strip_jump_poll(bContext *C)
static wmOperatorStatus sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op)
bool sequencer_view_has_preview_poll(bContext *C)
bool check_show_imbuf(const SpaceSeq &sseq)
static wmOperatorStatus sequencer_reassign_inputs_exec(bContext *C, wmOperator *op)
static wmOperatorStatus sequencer_meta_toggle_exec(bContext *C, wmOperator *)
void SEQUENCER_OT_swap(wmOperatorType *ot)
void SEQUENCER_OT_duplicate(wmOperatorType *ot)
static wmOperatorStatus sequencer_scene_frame_range_update_exec(bContext *C, wmOperator *)
static const EnumPropertyItem prop_split_types[]
wmOperatorStatus sequencer_clipboard_paste_exec(bContext *C, wmOperator *op)
const EnumPropertyItem prop_side_types[]
static bool sequencer_scene_frame_range_update_poll(bContext *C)
int sequencer_image_seq_get_minmax_frame(wmOperator *op, int sfra, int *r_minframe, int *r_numdigits)
void SEQUENCER_OT_delete(wmOperatorType *ot)
static wmOperatorStatus sequencer_strip_transform_clear_exec(bContext *C, wmOperator *op)
static SlipData * slip_data_init(const Scene *scene)
void SEQUENCER_OT_meta_separate(wmOperatorType *ot)
static bool sequencer_effect_poll(bContext *C)
bool sequencer_view_strips_poll(bContext *C)
static void slip_handle_num_input(const bContext *C, wmOperator *op, ScrArea *area, SlipData *data, Scene *scene)
static wmOperatorStatus sequencer_lock_exec(bContext *C, wmOperator *)
static bool strip_is_parent(const Strip *par, const Strip *strip)
void slip_modal_keymap(wmKeyConfig *keyconf)
static wmOperatorStatus sequencer_slip_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_export_subtitles(wmOperatorType *ot)
static bool sequencer_swap_inputs_poll(bContext *C)
static wmOperatorStatus sequencer_change_scene_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static wmOperatorStatus sequencer_unlock_exec(bContext *C, wmOperator *)
bool sequencer_strip_has_path_poll(bContext *C)
static wmOperatorStatus sequencer_swap_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_swap_data(wmOperatorType *ot)
void SEQUENCER_OT_disconnect(wmOperatorType *ot)
void SEQUENCER_OT_split(wmOperatorType *ot)
static bool strip_jump_internal(Scene *scene, const short side, const bool do_skip_mute, const bool do_center)
static bool sequencer_strip_color_tag_set_poll(bContext *C)
bool check_show_maskedit(SpaceSeq *sseq, Scene *scene)
static bool sequencer_refresh_all_poll(bContext *C)
static wmOperatorStatus sequencer_swap_data_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_cursor_set(wmOperatorType *ot)
void SEQUENCER_OT_strip_jump(wmOperatorType *ot)
static wmOperatorStatus sequencer_strip_color_tag_set_exec(bContext *C, wmOperator *op)
bool render_is_muted(const ListBase *channels, const Strip *strip)
Definition render.cc:2081
void relations_strip_free_anim(Strip *strip)
void prefetch_stop(Scene *scene)
Definition prefetch.cc:283
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
bool disconnect(Strip *strip)
void relations_invalidate_cache(Scene *scene, Strip *strip)
EffectHandle strip_effect_handle_get(Strip *strip)
Definition effects.cc:249
bool are_strips_connected_together(blender::VectorSet< Strip * > &strip_list)
SeqTimelineChannel * channel_get_by_index(const ListBase *channels, const int channel_index)
Definition channels.cc:65
ListBase * channels_displayed_get(const Editing *ed)
Definition channels.cc:28
void edit_remove_flagged_strips(Scene *scene, ListBase *seqbase)
float time_content_end_frame_get(const Scene *scene, const Strip *strip)
bool relations_render_loop_check(Strip *strip_main, Strip *strip)
void thumbnail_cache_invalidate_strip(Scene *scene, const Strip *strip)
void edit_flag_for_removal(Scene *scene, ListBase *seqbase, Strip *strip)
VectorSet< Strip * > query_selected_strips(ListBase *seqbase)
Definition iterator.cc:127
void transform_translate_strip(Scene *evil_scene, Strip *strip, int delta)
void strip_channel_set(Strip *strip, int channel)
void media_presence_free(Scene *scene)
bool transform_test_overlap(const Scene *scene, Strip *strip1, Strip *strip2)
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:272
void meta_stack_set(const Scene *scene, Strip *dst)
Definition sequencer.cc:461
void edit_strip_name_set(Scene *scene, Strip *strip, const char *new_name)
int time_left_handle_frame_get(const Scene *, const Strip *strip)
void animation_duplicate_backup_to_scene(Scene *scene, Strip *strip, AnimationBackup *backup)
Definition animation.cc:205
void offset_animdata(const Scene *scene, Strip *strip, float ofs)
Definition animation.cc:42
const char * strip_give_name(const Strip *strip)
void relations_invalidate_cache_raw(Scene *scene, Strip *strip)
void connect(Strip *strip1, Strip *strip2)
float time_start_frame_get(const Strip *strip)
bool transform_single_image_check(const Strip *strip)
Strip * strip_duplicate_recursive(const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, Strip *strip, int dupe_flag)
Definition sequencer.cc:645
void add_reload_new_file(Main *bmain, Scene *scene, Strip *strip, const bool lock_range)
Definition strip_add.cc:529
Strip * select_active_get(const Scene *scene)
void for_each_callback(ListBase *seqbase, ForEachFunc callback, void *user_data)
Definition iterator.cc:59
void iterator_set_expand(const Scene *scene, ListBase *seqbase, VectorSet< Strip * > &strips, void strip_query_func(const Scene *scene, Strip *strip_reference, ListBase *seqbase, VectorSet< Strip * > &strips))
Definition iterator.cc:82
bool select_active_get_pair(Scene *scene, Strip **r_strip_act, Strip **r_strip_other)
bool time_strip_intersects_frame(const Scene *scene, const Strip *strip, const int timeline_frame)
void time_slip_strip(const Scene *scene, Strip *strip, int frame_delta, float subframe_delta, bool slip_keyframes)
void transform_offset_after_frame(Scene *scene, ListBase *seqbase, const int delta, const int timeline_frame)
const char * get_default_stripname_by_type(int type)
void animation_backup_original(Scene *scene, AnimationBackup *backup)
Definition animation.cc:91
void select_active_set(Scene *scene, Strip *strip)
void cache_cleanup(Scene *scene)
bool edit_strip_swap(Scene *scene, Strip *strip_a, Strip *strip_b, const char **r_error_str)
Definition strip_edit.cc:44
bool transform_is_locked(ListBase *channels, const Strip *strip)
void strip_unique_name_set(Scene *scene, ListBase *seqbasep, Strip *strip)
void animation_restore_original(Scene *scene, AnimationBackup *backup)
Definition animation.cc:113
void time_left_handle_frame_set(const Scene *scene, Strip *strip, int timeline_frame)
void query_strip_connected_and_effect_chain(const Scene *scene, Strip *reference_strip, ListBase *seqbase, VectorSet< Strip * > &r_strips)
Definition iterator.cc:260
ListBase * active_seqbase_get(const Editing *ed)
Definition sequencer.cc:420
void time_right_handle_frame_set(const Scene *scene, Strip *strip, int timeline_frame)
Strip * meta_stack_pop(Editing *ed)
Definition sequencer.cc:485
bool transform_strip_can_be_translated(const Strip *strip)
void relations_free_imbuf(Scene *scene, ListBase *seqbase, bool for_render)
Strip * strip_alloc(ListBase *lb, int timeline_frame, int channel, int type)
Definition sequencer.cc:130
Strip * edit_strip_split(Main *bmain, Scene *scene, ListBase *seqbase, Strip *strip, const int timeline_frame, const eSplitMethod method, const bool ignore_connections, const char **r_error)
void strip_lookup_invalidate(const Editing *ed)
void ensure_unique_name(Strip *strip, Scene *scene)
Mask * active_mask_get(Scene *scene)
void seqbase_duplicate_recursive(const Scene *scene_src, Scene *scene_dst, ListBase *nseqbase, const ListBase *seqbase, int dupe_flag, const int flag)
Definition sequencer.cc:692
bool edit_remove_gaps(Scene *scene, ListBase *seqbase, const int initial_frame, const bool remove_all_gaps)
bool transform_seqbase_shuffle(ListBase *seqbasep, Strip *test, Scene *evil_scene)
int time_find_next_prev_edit(Scene *scene, int timeline_frame, const short side, const bool do_skip_mute, const bool do_center, const bool do_unselected)
void set_scale_to_fit(const Strip *strip, const int image_width, const int image_height, const int preview_width, const int preview_height, const eSeqImageFitMethod fit_method)
StripElem * render_give_stripelem(const Scene *scene, const Strip *strip, int timeline_frame)
Definition render.cc:234
float2 image_preview_unit_from_px(const Scene *scene, const float2 co_src)
int effect_get_num_inputs(int strip_type)
Definition effects.cc:286
VecBase< float, 2 > float2
static blender::bke::bNodeSocketTemplate inputs[]
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
bool RNA_struct_property_is_set_ex(PointerRNA *ptr, const char *identifier, bool use_ghost)
void RNA_int_set(PointerRNA *ptr, const char *name, int value)
void RNA_float_get_array(PointerRNA *ptr, const char *name, float *values)
void RNA_property_update(bContext *C, PointerRNA *ptr, PropertyRNA *prop)
void RNA_string_get(PointerRNA *ptr, const char *name, char *value)
int RNA_int_get(PointerRNA *ptr, const char *name)
char * RNA_string_get_alloc(PointerRNA *ptr, const char *name, char *fixedbuf, int fixedlen, int *r_len)
float RNA_float_get(PointerRNA *ptr, const char *name)
void RNA_float_set(PointerRNA *ptr, const char *name, float value)
bool RNA_struct_property_is_set(PointerRNA *ptr, const char *identifier)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
void RNA_enum_set(PointerRNA *ptr, const char *name, int value)
void RNA_float_set_array(PointerRNA *ptr, const char *name, const float *values)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
int RNA_enum_get(PointerRNA *ptr, const char *name)
int RNA_property_collection_length(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_string_set(PointerRNA *ptr, PropertyRNA *prop, const char *value)
PropertyRNA * RNA_def_float(StructOrFunctionRNA *cont_, const char *identifier, const float default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_float_vector(StructOrFunctionRNA *cont_, const char *identifier, const int len, const float *default_value, const float hardmin, const float hardmax, const char *ui_name, const char *ui_description, const float softmin, const float softmax)
PropertyRNA * RNA_def_enum(StructOrFunctionRNA *cont_, const char *identifier, const EnumPropertyItem *items, const int default_value, const char *ui_name, const char *ui_description)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void RNA_def_property_translation_context(PropertyRNA *prop, const char *context)
void RNA_def_property_flag(PropertyRNA *prop, PropertyFlag flag)
void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc)
void RNA_def_property_ui_range(PropertyRNA *prop, double min, double max, double step, int precision)
PropertyRNA * RNA_def_int(StructOrFunctionRNA *cont_, const char *identifier, const int default_value, const int hardmin, const int hardmax, const char *ui_name, const char *ui_description, const int softmin, const int softmax)
const EnumPropertyItem rna_enum_dummy_NULL_items[]
Definition rna_rna.cc:26
const EnumPropertyItem rna_enum_strip_color_items[]
#define FLT_MAX
Definition stdcycles.h:14
bAction * action
char * rna_path
void * last
void * first
ListBase scenes
Definition BKE_main.hh:245
struct Editing * ed
struct RenderData r
struct AnimData * adt
struct UnitSettings unit
ListBase markers
float cursor[2]
StripTransform * transform
StripElem * stripdata
char dirpath[768]
char filename[256]
void * scene_sound
struct Strip * input1
StripData * data
struct Scene * scene
void * effectdata
struct bSound * sound
ListBase seqbase
struct Strip * next
float sound_offset
char name[64]
struct Strip * input2
ListBase channels
char filepath[1024]
VectorSet< Strip * > strips
void(* free)(Strip *strip, bool do_id_user)
void(* init)(Strip *strip)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
uiLayout & row(bool align)
void prop(PointerRNA *ptr, PropertyRNA *prop, int index, int value, eUI_Item_Flag flag, std::optional< blender::StringRef > name_opt, int icon, std::optional< blender::StringRef > placeholder=std::nullopt)
wmEventType type
Definition WM_types.hh:754
short val
Definition WM_types.hh:756
int mval[2]
Definition WM_types.hh:760
const void * modal_items
struct ReportList * reports
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
i
Definition text_draw.cc:230
uint len
void WM_event_add_fileselect(bContext *C, wmOperator *op)
wmEventHandler_Op * WM_event_add_modal_handler(bContext *C, wmOperator *op)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
@ EVT_MODAL_MAP
@ MOUSEMOVE
PointerRNA * ptr
Definition wm_files.cc:4226
wmOperatorType * ot
Definition wm_files.cc:4225
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:929
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:956
void WM_operator_properties_filesel(wmOperatorType *ot, const int filter, const short type, const eFileSel_Action action, const eFileSel_Flag flag, const short display, const short sort)
wmOperatorStatus WM_operator_props_popup_confirm_ex(bContext *C, wmOperator *op, const wmEvent *, std::optional< std::string > title, std::optional< std::string > confirm_text, const bool cancel_default)
wmOperatorStatus WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *)