Blender V5.0
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_fileops.h"
10#include "BLI_listbase.h"
11#include "BLI_math_vector.h"
12#include "BLI_path_utils.hh"
13#include "BLI_string.h"
14#include "BLI_string_ref.hh"
15#include "BLI_string_utf8.h"
16#include "BLI_string_utils.hh"
17#include "BLI_timecode.h"
18#include "BLI_utildefines.h"
19#include "BLI_vector.hh"
20
21#include "MEM_guardedalloc.h"
22
23#include "BLT_translation.hh"
24
25#include "DNA_anim_types.h"
26#include "DNA_scene_types.h"
27#include "DNA_sequence_types.h"
28#include "DNA_sound_types.h"
29
30#include "BKE_context.hh"
31#include "BKE_global.hh"
32#include "BKE_idtype.hh"
33#include "BKE_layer.hh"
34#include "BKE_library.hh"
35#include "BKE_main.hh"
36#include "BKE_report.hh"
37#include "BKE_sound.h"
38
39#include "SEQ_add.hh"
40#include "SEQ_animation.hh"
41#include "SEQ_channels.hh"
42#include "SEQ_connect.hh"
43#include "SEQ_edit.hh"
44#include "SEQ_effects.hh"
45#include "SEQ_iterator.hh"
46#include "SEQ_prefetch.hh"
47#include "SEQ_relations.hh"
48#include "SEQ_render.hh"
49#include "SEQ_select.hh"
50#include "SEQ_sequencer.hh"
52#include "SEQ_time.hh"
53#include "SEQ_transform.hh"
54#include "SEQ_utils.hh"
55
56#include "ANIM_action_legacy.hh"
57
58#include "WM_api.hh"
59#include "WM_types.hh"
60
61#include "RNA_define.hh"
62#include "RNA_enum_types.hh"
63#include "RNA_prototypes.hh"
64
65/* For menu, popup, icons, etc. */
66#include "ED_fileselect.hh"
67#include "ED_numinput.hh"
68#include "ED_object.hh"
69#include "ED_scene.hh"
70#include "ED_screen.hh"
71#include "ED_screen_types.hh"
72#include "ED_sequencer.hh"
73
75#include "UI_resources.hh"
76#include "UI_view2d.hh"
77
78#include "DEG_depsgraph.hh"
80
81/* Own include. */
82#include "sequencer_intern.hh"
83#include <cstddef>
84#include <fmt/format.h>
85
86namespace blender::ed::vse {
87
88/* -------------------------------------------------------------------- */
91
93{
94 return maskedit_poll(C);
95}
96
98{
99 if (sseq && sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
100 return (seq::active_mask_get(scene) != nullptr);
101 }
102
103 return false;
104}
105
107{
108 SpaceSeq *sseq = CTX_wm_space_seq(C);
109
110 if (sseq) {
112 return check_show_maskedit(sseq, scene);
113 }
114
115 return false;
116}
117
118bool check_show_imbuf(const SpaceSeq &sseq)
119{
120 return (sseq.mainb == SEQ_DRAW_IMG_IMBUF) &&
122}
123
124bool check_show_strip(const SpaceSeq &sseq)
125{
127}
128
130{
131 if (!BLI_str_startswith(fcurve->rna_path, "sequence_editor.strips_all[\"")) {
132 return false;
133 }
134
135 if (!BLI_str_endswith(fcurve->rna_path, "\"].color")) {
136 return false;
137 }
138
139 return true;
140}
141
143{
144 if (!scene->adt) {
145 return false;
146 }
147 if (!scene->adt->action) {
148 return false;
149 }
150
153 return true;
154 }
155 }
156
157 return false;
158}
159
161
162/* -------------------------------------------------------------------- */
165
167{
169 if (!scene) {
170 return false;
171 }
172 return (seq::editing_get(scene) != nullptr);
173}
174
176{
177 if (!sequencer_edit_poll(C)) {
178 return false;
179 }
180 ARegion *region = CTX_wm_region(C);
181 if (!(region && (region->regiontype == RGN_TYPE_CHANNELS))) {
182 return false;
183 }
184 return true;
185}
186
191
192#if 0 /* UNUSED */
193bool sequencer_strip_poll(bContext *C)
194{
195 Editing *ed;
196 return (((ed = seq::editing_get(CTX_data_sequencer_scene(C))) != nullptr) && (ed->act_strip != nullptr));
197}
198#endif
199
201{
203 if (!scene || !ID_IS_EDITABLE(&scene->id)) {
204 return false;
205 }
206 Editing *ed = seq::editing_get(scene);
207 return (ed && (ed->act_strip != nullptr));
208}
209
211{
213 if (!scene) {
214 return false;
215 }
216 Editing *ed = seq::editing_get(scene);
217 if (!ed) {
218 return false;
219 }
220 Strip *strip = ed->act_strip;
221 if (!strip) {
222 return false;
223 }
224 return STRIP_HAS_PATH(strip);
225}
226
228{
229 if (!sequencer_edit_poll(C)) {
230 return false;
231 }
232 SpaceSeq *sseq = CTX_wm_space_seq(C);
233 if (sseq == nullptr) {
234 return false;
235 }
237 (sseq->mainb == SEQ_DRAW_IMG_IMBUF)))
238 {
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{
252 if (!scene) {
253 return false;
254 }
255 Editing *ed = seq::editing_get(scene);
256 if (!ed) {
257 return false;
258 }
259 SpaceSeq *sseq = CTX_wm_space_seq(C);
260 if (sseq == nullptr) {
261 return false;
262 }
263 if (!(ELEM(sseq->view, SEQ_VIEW_PREVIEW) && (sseq->mainb == SEQ_DRAW_IMG_IMBUF))) {
264 return false;
265 }
266 ARegion *region = CTX_wm_region(C);
267 if (!(region && region->regiontype == RGN_TYPE_PREVIEW)) {
268 return false;
269 }
270
271 return true;
272}
273
275{
276 SpaceSeq *sseq = CTX_wm_space_seq(C);
277 if (sseq == nullptr) {
278 return false;
279 }
280 if (!check_show_strip(*sseq)) {
281 return false;
282 }
283 ARegion *region = CTX_wm_region(C);
284 if (!(region && region->regiontype == RGN_TYPE_WINDOW)) {
285 return false;
286 }
287 return true;
288}
289
291{
292 if (!sequencer_edit_poll(C)) {
293 return false;
294 }
296 Editing *ed = seq::editing_get(scene);
297
298 if (ed) {
299 Strip *active_strip = seq::select_active_get(scene);
300 if (active_strip && active_strip->is_effect()) {
301 return true;
302 }
303 }
304
305 return false;
306}
307
309{
310 if (!sequencer_edit_poll(C)) {
311 return false;
312 }
314 Strip *active_strip = seq::select_active_get(scene);
315
316 if (sequencer_effect_poll(C) && seq::effect_get_num_inputs(active_strip->type) == 2) {
317 return true;
318 }
319
320 return false;
321}
322
324
325/* -------------------------------------------------------------------- */
328
330{
331 WorkSpace *workspace = CTX_wm_workspace(&C);
332 if (!workspace || !workspace->sequencer_scene) {
333 return false;
334 }
335 if ((workspace->flags & WORKSPACE_SYNC_SCENE_TIME) == 0) {
336 return false;
337 }
338 SpaceSeq *sseq = CTX_wm_space_seq(&C);
339 if (!sseq) {
340 /* We only want to start syncing the time when we're in a sequence editor.
341 * Changing time in any other editor should just affect the active scene. */
342 return false;
343 }
344 return true;
345}
346
348{
351 if (screen && screen->animtimer) {
352 wmTimer *wt = screen->animtimer;
353 ScreenAnimData *sad = static_cast<ScreenAnimData *>(wt->customdata);
354 if (sad->do_scene_syncing) {
355 return sad->scene;
356 }
357 /* If we're playing a scene that's not a sequence scene, don't try and sync. */
358 return nullptr;
359 }
362 }
363 return nullptr;
364}
365
366const Strip *get_scene_strip_for_time_sync(const Scene *sequencer_scene)
367{
368 using namespace blender;
369 const Editing *ed = seq::editing_get(sequencer_scene);
370 if (!ed) {
371 return nullptr;
372 }
374 const ListBase *channels = seq::channels_displayed_get(ed);
376 sequencer_scene, seqbase, sequencer_scene->r.cfra);
377 /* Ignore effect strips, sound strips and muted strips. */
378 query_strips.remove_if([&](const Strip *strip) {
379 return strip->is_effect() || strip->type == STRIP_TYPE_SOUND_RAM ||
380 seq::render_is_muted(channels, strip);
381 });
382 Vector<Strip *> strips = query_strips.extract_vector();
383 /* Sort strips by channel. */
384 std::sort(strips.begin(), strips.end(), [](const Strip *a, const Strip *b) {
385 return a->channel > b->channel;
386 });
387 /* Get the top-most scene strip. */
388 for (const Strip *strip : strips) {
389 if (strip->type == STRIP_TYPE_SCENE) {
390 return strip;
391 }
392 }
393 return nullptr;
394}
395
397{
398 using namespace blender;
399 Scene *sequencer_scene = get_sequencer_scene_for_time_sync(C);
400 if (!sequencer_scene) {
401 return;
402 }
403
404 wmWindow *win = CTX_wm_window(&C);
405 const Strip *scene_strip = get_scene_strip_for_time_sync(sequencer_scene);
406 if (!scene_strip || !scene_strip->scene) {
407 /* No scene strip with scene found. Switch to pinned scene. */
408 Main *bmain = CTX_data_main(&C);
409 WM_window_set_active_scene(bmain, &C, win, sequencer_scene);
410 return;
411 }
412
414 Object *prev_obact = BKE_view_layer_active_object_get(view_layer);
415
416 Scene *active_scene = WM_window_get_active_scene(win);
417 if (active_scene != scene_strip->scene) {
418 /* Sync active scene in window. */
419 Main *bmain = CTX_data_main(&C);
420 WM_window_set_active_scene(bmain, &C, win, scene_strip->scene);
421 active_scene = scene_strip->scene;
422 }
423 Object *camera = [&]() -> Object * {
424 if (scene_strip->scene_camera) {
425 return scene_strip->scene_camera;
426 }
427 return scene_strip->scene->camera;
428 }();
429 if (camera) {
430 /* Sync camera in any 3D view that uses camera view. */
431 PointerRNA camera_ptr = RNA_id_pointer_create(&camera->id);
433 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
434 LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) {
435 if (sl->spacetype != SPACE_VIEW3D) {
436 continue;
437 }
438 View3D *view3d = reinterpret_cast<View3D *>(sl);
439 if (view3d->camera == camera) {
440 continue;
441 }
442 PointerRNA view3d_ptr = RNA_pointer_create_discrete(&screen->id, &RNA_SpaceView3D, view3d);
443 RNA_pointer_set(&view3d_ptr, "camera", camera_ptr);
444 }
445 }
446 }
447
448 /* Compute the scene time based on the scene strip. */
449 const float frame_index = seq::give_frame_index(
450 sequencer_scene, scene_strip, sequencer_scene->r.cfra) +
451 active_scene->r.sfra;
452 if (active_scene->r.flag & SCER_SHOW_SUBFRAME) {
453 active_scene->r.cfra = int(frame_index);
454 active_scene->r.subframe = frame_index - int(frame_index);
455 }
456 else {
457 active_scene->r.cfra = round_fl_to_int(frame_index);
458 active_scene->r.subframe = 0.0f;
459 }
460 FRAMENUMBER_MIN_CLAMP(active_scene->r.cfra);
461
462 /* Try to sync the object mode of the active object. */
463 if (prev_obact) {
465 if (obact && prev_obact->type == obact->type) {
466 ed::object::mode_set(&C, eObjectMode(prev_obact->mode));
467 }
468 }
469
473}
474
476
477/* -------------------------------------------------------------------- */
480
482{
484 const bool do_all = RNA_boolean_get(op->ptr, "all");
485 const Editing *ed = seq::editing_get(scene);
486
487 seq::edit_remove_gaps(scene, ed->current_strips(), scene->r.cfra, do_all);
488
491
492 return OPERATOR_FINISHED;
493}
494
496{
497 /* Identifiers. */
498 ot->name = "Remove Gaps";
499 ot->idname = "SEQUENCER_OT_gap_remove";
500 ot->description =
501 "Remove gap at current frame to first strip at the right, independent of selection or "
502 "locked state of strips";
503
504 /* API callbacks. */
505 // ot->invoke = sequencer_snap_invoke;
507 ot->poll = sequencer_edit_poll;
508
509 /* Flags. */
511
512 RNA_def_boolean(ot->srna, "all", false, "All Gaps", "Do all gaps to right of current frame");
513}
514
516
517/* -------------------------------------------------------------------- */
520
522{
524 const int frames = RNA_int_get(op->ptr, "frames");
525 const Editing *ed = seq::editing_get(scene);
526 seq::transform_offset_after_frame(scene, ed->current_strips(), frames, scene->r.cfra);
527
529
530 return OPERATOR_FINISHED;
531}
532
534{
535 /* Identifiers. */
536 ot->name = "Insert Gaps";
537 ot->idname = "SEQUENCER_OT_gap_insert";
538 ot->description =
539 "Insert gap at current frame to first strips at the right, independent of selection or "
540 "locked state of strips";
541
542 /* API callbacks. */
543 // ot->invoke = sequencer_snap_invoke;
545 ot->poll = sequencer_edit_poll;
546
547 /* Flags. */
549
550 RNA_def_int(ot->srna,
551 "frames",
552 10,
553 0,
554 INT_MAX,
555 "Frames",
556 "Frames to insert after current strip",
557 0,
558 1000);
559}
560
562
563/* -------------------------------------------------------------------- */
566
568{
570
571 Editing *ed = seq::editing_get(scene);
573 int snap_frame;
574
575 snap_frame = RNA_int_get(op->ptr, "frame");
576
577 /* Check meta-strips. */
578 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
579 if (strip->flag & SELECT && !seq::transform_is_locked(channels, strip) &&
581 {
582 if ((strip->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) == 0) {
584 scene, strip, (snap_frame - strip->startofs) - strip->start);
585 }
586 else {
587 if (strip->flag & SEQ_LEFTSEL) {
588 seq::time_left_handle_frame_set(scene, strip, snap_frame);
589 }
590 else { /* SEQ_RIGHTSEL */
591 seq::time_right_handle_frame_set(scene, strip, snap_frame);
592 }
593 }
594
596 }
597 }
598
599 /* Test for effects and overlap. */
600 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
601 if (strip->flag & SELECT && !seq::transform_is_locked(channels, strip)) {
602 strip->runtime.flag &= ~STRIP_OVERLAP;
603 if (seq::transform_test_overlap(scene, ed->current_strips(), strip)) {
604 seq::transform_seqbase_shuffle(ed->current_strips(), strip, scene);
605 }
606 }
607 }
608
609 /* Recalculate bounds of effect strips, offsetting the keyframes if not snapping any handle. */
610 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
611 if (strip->is_effect()) {
612 const bool either_handle_selected = (strip->flag & (SEQ_LEFTSEL | SEQ_RIGHTSEL)) != 0;
613
614 if (strip->input1 && (strip->input1->flag & SELECT)) {
615 if (!either_handle_selected) {
617 scene, strip, (snap_frame - seq::time_left_handle_frame_get(scene, strip)));
618 }
619 }
620 else if (strip->input2 && (strip->input2->flag & SELECT)) {
621 if (!either_handle_selected) {
623 scene, strip, (snap_frame - seq::time_left_handle_frame_get(scene, strip)));
624 }
625 }
626 }
627 }
628
631
632 return OPERATOR_FINISHED;
633}
634
636 wmOperator *op,
637 const wmEvent * /*event*/)
638{
640
641 int snap_frame;
642
643 snap_frame = scene->r.cfra;
644
645 RNA_int_set(op->ptr, "frame", snap_frame);
646 return sequencer_snap_exec(C, op);
647}
648
650{
651 /* Identifiers. */
652 ot->name = "Snap Strips to the Current Frame";
653 ot->idname = "SEQUENCER_OT_snap";
654 ot->description = "Frame where selected strips will be snapped";
655
656 /* API callbacks. */
657 ot->invoke = sequencer_snap_invoke;
658 ot->exec = sequencer_snap_exec;
659 ot->poll = sequencer_edit_poll;
660
661 /* Flags. */
663
664 RNA_def_int(ot->srna,
665 "frame",
666 0,
667 INT_MIN,
668 INT_MAX,
669 "Frame",
670 "Frame where selected strips will be snapped",
671 INT_MIN,
672 INT_MAX);
673}
674
676
677/* -------------------------------------------------------------------- */
680
681/* Modal Keymap */
682enum {
688};
689
711
713{
714 static const EnumPropertyItem modal_items[] = {
715 {SLIP_MODAL_CONFIRM, "CONFIRM", 0, "Confirm", ""},
716 {SLIP_MODAL_CANCEL, "CANCEL", 0, "Cancel", ""},
717
718 {SLIP_MODAL_PRECISION_ENABLE, "PRECISION_ENABLE", 0, "Precision Enable", ""},
719 {SLIP_MODAL_PRECISION_DISABLE, "PRECISION_DISABLE", 0, "Precision Disable", ""},
720 {SLIP_MODAL_CLAMP_TOGGLE, "CLAMP_TOGGLE", 0, "Clamp Toggle", ""},
721
722 {0, nullptr, 0, nullptr, nullptr},
723 };
724
725 wmKeyMap *keymap = WM_modalkeymap_find(keyconf, "Slip Modal");
726
727 /* This function is called for each space-type, only needs to add map once. */
728 if (keymap && keymap->modal_items) {
729 return;
730 }
731
732 keymap = WM_modalkeymap_ensure(keyconf, "Slip Modal", modal_items);
733
734 /* Assign map to operators. */
735 WM_modalkeymap_assign(keymap, "SEQUENCER_OT_slip");
736}
737
738static void slip_draw_status(bContext *C, const wmOperator *op)
739{
740 SlipData *data = static_cast<SlipData *>(op->customdata);
741
743
744 status.opmodal(IFACE_("Confirm"), op->type, SLIP_MODAL_CONFIRM);
745 status.opmodal(IFACE_("Cancel"), op->type, SLIP_MODAL_CANCEL);
746
747 status.opmodal(IFACE_("Precision"), op->type, SLIP_MODAL_PRECISION_ENABLE, data->precision);
748
749 if (data->can_clamp) {
750 status.opmodal(IFACE_("Clamp"), op->type, SLIP_MODAL_CLAMP_TOGGLE, data->clamp);
751 }
752 if (data->clamp_warning) {
753 status.item(TIP_("Not enough content to clamp strip(s)"), ICON_ERROR);
754 }
755}
756
757static void slip_update_header(const Scene *scene,
758 ScrArea *area,
759 SlipData *data,
760 const float offset)
761{
762 if (area == nullptr) {
763 return;
764 }
765
766 char msg[UI_MAX_DRAW_STR];
767 if (hasNumInput(&data->num_input)) {
768 char num_str[NUM_STR_REP_LEN];
769 outputNumInput(&data->num_input, num_str, scene->unit);
770 SNPRINTF_UTF8(msg, IFACE_("Slip Offset: Frames: %s"), num_str);
771 }
772 else {
773 int frame_offset = std::trunc(offset);
774 if (data->show_subframe) {
775 float subframe_offset_sec = (offset - std::trunc(offset)) / scene->frames_per_second();
776 SNPRINTF_UTF8(msg,
777 IFACE_("Slip Offset: Frames: %d Sound Offset: %.3f"),
778 frame_offset,
779 subframe_offset_sec);
780 }
781 else {
782 SNPRINTF_UTF8(msg, IFACE_("Slip Offset: Frames: %d"), frame_offset);
783 }
784 }
785
786 ED_area_status_text(area, msg);
787}
788
789static SlipData *slip_data_init(bContext *C, const wmOperator *op, const wmEvent *event)
790{
791 const Scene *scene = CTX_data_sequencer_scene(C);
792 const Editing *ed = seq::editing_get(scene);
793 const View2D *v2d = UI_view2d_fromcontext(C);
794
795 SlipData *data = MEM_new<SlipData>("slipdata");
796
797 VectorSet<Strip *> strips;
798 if (RNA_boolean_get(op->ptr, "use_cursor_position") && event) {
799 Strip *strip = strip_under_mouse_get(scene, v2d, event->mval);
800 if (strip) {
801 strips.add(strip);
802 }
803 if (!RNA_boolean_get(op->ptr, "ignore_connections")) {
805 for (Strip *connection : connections) {
806 strips.add(connection);
807 }
808 }
809 }
810 else {
811 strips = seq::query_selected_strips(ed->current_strips());
812 }
813
815 strips.remove_if([&](Strip *strip) {
816 return (seq::transform_single_image_check(strip) || seq::transform_is_locked(channels, strip));
817 });
818 if (strips.is_empty()) {
819 MEM_SAFE_DELETE(data);
820 return nullptr;
821 }
822 data->strips = strips;
823
824 data->show_subframe = false;
825 data->clamp_warning = false;
826 data->can_clamp = false;
827
828 data->clamp = true;
829 for (Strip *strip : strips) {
831
832 /* If any strips start out with hold offsets visible, disable clamping on initialization. */
833 if (strip->startofs < 0 || strip->endofs < 0) {
834 data->clamp = false;
835 }
836 /* If any strips do not have enough underlying content to
837 * fill their bounds, show a warning. */
838 if (strip->len < seq::time_right_handle_frame_get(scene, strip) -
840 {
841 data->clamp_warning = true;
842 }
843 /* Strip exists with enough content, we can clamp. */
844 else {
845 data->can_clamp = true;
846 }
847 if (strip->type == STRIP_TYPE_SOUND_RAM) {
848 data->show_subframe = true;
849 }
850 }
851
852 return data;
853}
854
856{
858 ScrArea *area = CTX_wm_area(C);
860
861 SlipData *data = slip_data_init(C, op, event);
862 if (data == nullptr) {
863 return OPERATOR_CANCELLED;
864 }
865 op->customdata = data;
866
867 initNumInput(&data->num_input);
869 v2d, event->mval[0], event->mval[1], &data->init_mouse_co[0], &data->init_mouse_co[1]);
870 data->precision = false;
871 data->prev_offset = 0.0f;
872 data->prev_mval_x = event->mval[0];
873 data->virtual_mval_x = event->mval[0];
874
875 slip_draw_status(C, op);
876 slip_update_header(scene, area, data, 0.0f);
877
879
880 /* Enable cursor wrapping. */
882
883 /* Notify so we draw extensions immediately. */
885
887}
888
890 bContext *C, wmOperator *op, Scene *scene, SlipData *data, const float delta)
891{
892 float new_offset = data->prev_offset + delta;
893 /* Calculate rounded whole frames between offsets, which cannot be determined from `delta` alone.
894 * For example, 0.9 -> 1.0 would have a `delta` of 0.1 and a `frame_delta` of 1. */
895 int frame_delta = std::trunc(new_offset) - std::trunc(data->prev_offset);
896
897 float subframe_delta = 0.0f;
898 /* Only apply subframe delta if the input is not an integer. */
899 if (std::trunc(delta) != delta) {
900 /* Note that `subframe_delta` has opposite sign to `frame_delta`
901 * when `abs(delta)` < `abs(frame_delta)` to undo its effect. */
902 subframe_delta = delta - frame_delta;
903 }
904
905 bool slip_keyframes = RNA_boolean_get(op->ptr, "slip_keyframes");
906 for (Strip *strip : data->strips) {
907 seq::time_slip_strip(scene, strip, frame_delta, subframe_delta, slip_keyframes);
909
911 /* Reconstruct handle clamp state from first principles. */
912 if (data->clamp == true) {
914 strip->runtime.flag |= STRIP_CLAMPED_LH;
915 }
916 if (seq::time_right_handle_frame_get(scene, strip) ==
918 {
919 strip->runtime.flag |= STRIP_CLAMPED_RH;
920 }
921 }
922 }
923
925
926 RNA_float_set(op->ptr, "offset", new_offset);
927 data->prev_offset = new_offset;
928}
929
930static void slip_cleanup(bContext *C, wmOperator *op, Scene *scene)
931{
932 ScrArea *area = CTX_wm_area(C);
933 SlipData *data = static_cast<SlipData *>(op->customdata);
934
935 for (Strip *strip : data->strips) {
938 }
939
940 MEM_SAFE_DELETE(data);
941 if (area) {
942 ED_area_status_text(area, nullptr);
943 }
944 ED_workspace_status_text(C, nullptr);
947}
948
949/* Returns clamped offset delta relative to current strip positions,
950 * which is the sum of the frame delta and the subframe delta. */
951static float slip_apply_clamp(const Scene *scene, const SlipData *data, float *r_offset)
952{
953 float offset_delta = *r_offset - data->prev_offset;
954
955 if (data->can_clamp) {
956 for (Strip *strip : data->strips) {
957 const float unclamped_start = seq::time_start_frame_get(strip) + strip->sound_offset +
958 offset_delta;
959 const float unclamped_end = seq::time_content_end_frame_get(scene, strip) +
960 strip->sound_offset + offset_delta;
961
962 const float left_handle = seq::time_left_handle_frame_get(scene, strip);
963 const float right_handle = seq::time_right_handle_frame_get(scene, strip);
964
965 float diff = 0;
966
967 /* Clamp hold offsets if the option is currently enabled
968 * and if there are enough frames to fill the strip. */
969 if (data->clamp && strip->len >= right_handle - left_handle) {
970 if (unclamped_start > left_handle) {
971 diff = left_handle - unclamped_start;
972 }
973 else if (unclamped_end < right_handle) {
974 diff = right_handle - unclamped_end;
975 }
976 }
977 /* Always make sure each strip contains at least 1 frame of content,
978 * even if the user hasn't enabled clamping. */
979 else {
980 if (unclamped_start > right_handle - 1) {
981 diff = right_handle - 1 - unclamped_start;
982 }
983
984 if (unclamped_end < left_handle + 1) {
985 diff = left_handle + 1 - unclamped_end;
986 }
987 }
988
989 *r_offset += diff;
990 offset_delta += diff;
991 }
992 }
993
994 return offset_delta;
995}
996
998{
1000
1001 SlipData *data = slip_data_init(C, op, nullptr);
1002 if (data == nullptr) {
1003 return OPERATOR_CANCELLED;
1004 }
1005 op->customdata = data;
1006
1007 float offset = RNA_float_get(op->ptr, "offset");
1008 slip_apply_clamp(scene, data, &offset);
1009
1010 slip_strips_delta(C, op, scene, data, offset);
1011
1012 slip_cleanup(C, op, scene);
1013 return OPERATOR_FINISHED;
1014}
1015
1017 bContext *C, wmOperator *op, ScrArea *area, SlipData *data, Scene *scene)
1018{
1019 float offset;
1020 applyNumInput(&data->num_input, &offset);
1021
1022 const float offset_delta = slip_apply_clamp(scene, data, &offset);
1023 slip_update_header(scene, area, data, offset);
1024 RNA_float_set(op->ptr, "offset", offset);
1025
1026 slip_strips_delta(C, op, scene, data, offset_delta);
1027
1029}
1030
1032{
1035 SlipData *data = static_cast<SlipData *>(op->customdata);
1036 ScrArea *area = CTX_wm_area(C);
1037 const bool has_num_input = hasNumInput(&data->num_input);
1038
1039 if (event->val == KM_PRESS && handleNumInput(C, &data->num_input, event)) {
1040 slip_handle_num_input(C, op, area, data, scene);
1042 }
1043
1044 if (event->type == EVT_MODAL_MAP) {
1045 switch (event->val) {
1046 case SLIP_MODAL_CONFIRM: {
1047 slip_cleanup(C, op, scene);
1048 return OPERATOR_FINISHED;
1049 }
1050 case SLIP_MODAL_CANCEL: {
1051 slip_strips_delta(C, op, scene, data, -data->prev_offset);
1052 slip_cleanup(C, op, scene);
1053 return OPERATOR_CANCELLED;
1054 }
1056 if (!has_num_input) {
1057 data->precision = true;
1058 /* Align virtual mouse pointer with the truncated frame to avoid jumps. */
1059 float mouse_co[2];
1060 UI_view2d_region_to_view(v2d, data->virtual_mval_x, 0.0f, &mouse_co[0], &mouse_co[1]);
1061 float offset = mouse_co[0] - data->init_mouse_co[0];
1062 float subframe_offset = offset - std::trunc(offset);
1063 data->virtual_mval_x += -subframe_offset * UI_view2d_scale_get_x(v2d);
1064 }
1065 break;
1067 if (!has_num_input) {
1068 data->precision = false;
1069 /* If we exit precision mode, make sure we undo the fractional adjustments and align the
1070 * virtual mouse pointer. */
1071 float to_nearest_frame = -(data->prev_offset - round_fl_to_int(data->prev_offset));
1072 slip_strips_delta(C, op, scene, data, to_nearest_frame);
1073 data->virtual_mval_x += to_nearest_frame * UI_view2d_scale_get_x(v2d);
1074 }
1075 break;
1077 data->clamp = !data->clamp;
1078 break;
1079 default:
1080 break;
1081 }
1082 }
1083
1084 if (event->type == MOUSEMOVE || event->val == SLIP_MODAL_PRECISION_DISABLE ||
1085 event->val == SLIP_MODAL_CLAMP_TOGGLE)
1086 {
1087 if (!has_num_input) {
1088 float mouse_x_delta = event->mval[0] - data->prev_mval_x;
1089 data->prev_mval_x += mouse_x_delta;
1090 if (data->precision) {
1091 mouse_x_delta *= 0.1f;
1092 }
1093 data->virtual_mval_x += mouse_x_delta;
1094
1095 float mouse_co[2];
1096 UI_view2d_region_to_view(v2d, data->virtual_mval_x, 0.0f, &mouse_co[0], &mouse_co[1]);
1097 float offset = mouse_co[0] - data->init_mouse_co[0];
1098 if (!data->precision) {
1099 offset = std::trunc(offset);
1100 }
1101
1102 float clamped_offset = offset;
1103 float clamped_offset_delta = slip_apply_clamp(scene, data, &clamped_offset);
1104 /* Also adjust virtual mouse pointer after clamp is applied. */
1105 data->virtual_mval_x += (clamped_offset - offset) * UI_view2d_scale_get_x(v2d);
1106
1107 slip_strips_delta(C, op, scene, data, clamped_offset_delta);
1108 slip_update_header(scene, area, data, clamped_offset);
1109
1111 }
1112 }
1113
1114 slip_draw_status(C, op);
1115
1117}
1118
1120{
1121 /* Identifiers. */
1122 ot->name = "Slip Strips";
1123 ot->idname = "SEQUENCER_OT_slip";
1124 ot->description = "Slip the contents of selected strips";
1125
1126 /* API callbacks. */
1127 ot->invoke = sequencer_slip_invoke;
1128 ot->modal = sequencer_slip_modal;
1129 ot->exec = sequencer_slip_exec;
1130 ot->poll = sequencer_edit_poll;
1131
1132 /* Flags. */
1134
1135 /* Properties. */
1136 PropertyRNA *prop;
1137
1138 prop = RNA_def_float(ot->srna,
1139 "offset",
1140 0,
1141 -FLT_MAX,
1142 FLT_MAX,
1143 "Offset",
1144 "Offset to the data of the strip",
1145 -FLT_MAX,
1146 FLT_MAX);
1147 RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 100, 0);
1148 RNA_def_boolean(ot->srna,
1149 "slip_keyframes",
1150 false,
1151 "Slip Keyframes",
1152 "Move the keyframes alongside the media");
1153 RNA_def_boolean(ot->srna,
1154 "use_cursor_position",
1155 false,
1156 "Use Cursor Position",
1157 "Slip strips under mouse cursor instead of all selected strips");
1158 RNA_def_boolean(ot->srna,
1159 "ignore_connections",
1160 false,
1161 "Ignore Connections",
1162 "Do not slip connected strips if using cursor position");
1163}
1164
1166
1167/* -------------------------------------------------------------------- */
1170
1172{
1175
1176 for (Strip *strip : strips) {
1177 if (!RNA_boolean_get(op->ptr, "unselected")) {
1178 if (strip->flag & SELECT) {
1179 strip->flag |= SEQ_MUTE;
1180 seq::relations_invalidate_cache(scene, strip);
1181 }
1182 }
1183 else {
1184 if ((strip->flag & SELECT) == 0) {
1185 strip->flag |= SEQ_MUTE;
1186 seq::relations_invalidate_cache(scene, strip);
1187 }
1188 }
1189 }
1190
1192
1195
1196 return OPERATOR_FINISHED;
1197}
1198
1200{
1201 /* Identifiers. */
1202 ot->name = "Mute Strips";
1203 ot->idname = "SEQUENCER_OT_mute";
1204 ot->description = "Mute (un)selected strips";
1205
1206 /* API callbacks. */
1207 ot->exec = sequencer_mute_exec;
1208 ot->poll = sequencer_edit_poll;
1209
1210 /* Flags. */
1211 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1212
1214 ot->srna, "unselected", false, "Unselected", "Mute unselected rather than selected strips");
1215}
1216
1218
1219/* -------------------------------------------------------------------- */
1222
1224{
1226 Editing *ed = seq::editing_get(scene);
1227 ARegion *region = CTX_wm_region(C);
1228 const bool is_preview = region && (region->regiontype == RGN_TYPE_PREVIEW) &&
1230 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
1231 if (is_preview) {
1232 if (seq::time_strip_intersects_frame(scene, strip, scene->r.cfra) &&
1233 strip->type != STRIP_TYPE_SOUND_RAM)
1234 {
1235 strip->flag &= ~SEQ_MUTE;
1236 seq::relations_invalidate_cache(scene, strip);
1237 }
1238 }
1239 else if (!RNA_boolean_get(op->ptr, "unselected")) {
1240 if (strip->flag & SELECT) {
1241 strip->flag &= ~SEQ_MUTE;
1242 seq::relations_invalidate_cache(scene, strip);
1243 }
1244 }
1245 else {
1246 if ((strip->flag & SELECT) == 0) {
1247 strip->flag &= ~SEQ_MUTE;
1248 seq::relations_invalidate_cache(scene, strip);
1249 }
1250 }
1251 }
1252
1254
1257
1258 return OPERATOR_FINISHED;
1259}
1260
1262{
1263 /* Identifiers. */
1264 ot->name = "Unmute Strips";
1265 ot->idname = "SEQUENCER_OT_unmute";
1266 ot->description = "Unmute (un)selected strips";
1267
1268 /* API callbacks. */
1269 ot->exec = sequencer_unmute_exec;
1270 ot->poll = sequencer_edit_poll;
1271
1272 /* Flags. */
1273 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1274
1275 RNA_def_boolean(ot->srna,
1276 "unselected",
1277 false,
1278 "Unselected",
1279 "Unmute unselected rather than selected strips");
1280}
1281
1283
1284/* -------------------------------------------------------------------- */
1287
1289{
1291 Editing *ed = seq::editing_get(scene);
1292
1293 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
1294 if (strip->flag & SELECT) {
1295 strip->flag |= SEQ_LOCK;
1296 }
1297 }
1298
1300
1301 return OPERATOR_FINISHED;
1302}
1303
1305{
1306 /* Identifiers. */
1307 ot->name = "Lock Strips";
1308 ot->idname = "SEQUENCER_OT_lock";
1309 ot->description = "Lock strips so they cannot be transformed";
1310
1311 /* API callbacks. */
1312 ot->exec = sequencer_lock_exec;
1313 ot->poll = sequencer_edit_poll;
1314
1315 /* Flags. */
1316 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1317}
1318
1320
1321/* -------------------------------------------------------------------- */
1324
1326{
1328 Editing *ed = seq::editing_get(scene);
1329
1330 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
1331 if (strip->flag & SELECT) {
1332 strip->flag &= ~SEQ_LOCK;
1333 }
1334 }
1335
1337
1338 return OPERATOR_FINISHED;
1339}
1340
1342{
1343 /* Identifiers. */
1344 ot->name = "Unlock Strips";
1345 ot->idname = "SEQUENCER_OT_unlock";
1346 ot->description = "Unlock strips so they can be transformed";
1347
1348 /* API callbacks. */
1349 ot->exec = sequencer_unlock_exec;
1350 ot->poll = sequencer_edit_poll;
1351
1352 /* Flags. */
1353 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1354}
1355
1357
1358/* -------------------------------------------------------------------- */
1361
1363{
1365 Editing *ed = seq::editing_get(scene);
1366 ListBase *active_seqbase = seq::active_seqbase_get(ed);
1367
1369
1370 if (selected.is_empty()) {
1371 return OPERATOR_CANCELLED;
1372 }
1373
1374 const bool toggle = RNA_boolean_get(op->ptr, "toggle");
1375 if (toggle && seq::are_strips_connected_together(selected)) {
1376 seq::disconnect(selected);
1377 }
1378 else {
1379 seq::connect(selected);
1380 }
1381
1383 return OPERATOR_FINISHED;
1384}
1385
1387{
1388 ot->name = "Connect Strips";
1389 ot->idname = "SEQUENCER_OT_connect";
1390 ot->description = "Link selected strips together for simplified group selection";
1391
1392 ot->exec = sequencer_connect_exec;
1393 ot->poll = sequencer_edit_poll;
1394
1395 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1396
1397 RNA_def_boolean(ot->srna, "toggle", true, "Toggle", "Toggle strip connections");
1398}
1399
1401
1402/* -------------------------------------------------------------------- */
1405
1407{
1409 Editing *ed = seq::editing_get(scene);
1410 ListBase *active_seqbase = seq::active_seqbase_get(ed);
1411
1413
1414 if (seq::disconnect(selected)) {
1416 return OPERATOR_FINISHED;
1417 }
1418 return OPERATOR_CANCELLED;
1419}
1420
1422{
1423 ot->name = "Disconnect Strips";
1424 ot->idname = "SEQUENCER_OT_disconnect";
1425 ot->description = "Unlink selected strips so that they can be selected individually";
1426
1428 ot->poll = sequencer_edit_poll;
1429
1430 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1431}
1432
1434
1435/* -------------------------------------------------------------------- */
1438
1440{
1441 Main *bmain = CTX_data_main(C);
1443 Editing *ed = seq::editing_get(scene);
1444 const bool adjust_length = RNA_boolean_get(op->ptr, "adjust_length");
1445
1446 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
1447 if (strip->flag & SELECT) {
1448 seq::add_reload_new_file(bmain, scene, strip, !adjust_length);
1450
1451 if (adjust_length) {
1452 if (seq::transform_test_overlap(scene, ed->current_strips(), strip)) {
1453 seq::transform_seqbase_shuffle(ed->current_strips(), strip, scene);
1454 }
1455 }
1456 }
1457 }
1458
1460
1461 return OPERATOR_FINISHED;
1462}
1463
1465{
1466 PropertyRNA *prop;
1467
1468 /* Identifiers. */
1469 ot->name = "Reload Strips";
1470 ot->idname = "SEQUENCER_OT_reload";
1471 ot->description = "Reload strips in the sequencer";
1472
1473 /* API callbacks. */
1474 ot->exec = sequencer_reload_exec;
1475 ot->poll = sequencer_edit_poll;
1476
1477 /* Flags. */
1478 ot->flag = OPTYPE_REGISTER; /* No undo, the data changed is stored outside 'main'. */
1479
1480 prop = RNA_def_boolean(ot->srna,
1481 "adjust_length",
1482 false,
1483 "Adjust Length",
1484 "Adjust length of strips to their data length");
1486}
1487
1489
1490/* -------------------------------------------------------------------- */
1493
1495{
1496 if (G.is_rendering) {
1497 return false;
1498 }
1499 return sequencer_edit_poll(C);
1500}
1501
1503{
1505 Editing *ed = seq::editing_get(scene);
1506
1507 seq::relations_free_imbuf(scene, &ed->seqbase, false);
1509 seq::cache_cleanup(scene);
1510
1512
1513 return OPERATOR_FINISHED;
1514}
1515
1517{
1518 /* Identifiers. */
1519 ot->name = "Refresh Sequencer";
1520 ot->idname = "SEQUENCER_OT_refresh_all";
1521 ot->description = "Refresh the sequencer editor";
1522
1523 /* API callbacks. */
1526}
1527
1529
1530/* -------------------------------------------------------------------- */
1533
1535{
1536 if (inputs.size() > 2) {
1537 return "Cannot apply effect to more than 2 strips with video content";
1538 }
1539 if (num_inputs == 2 && inputs.size() != 2) {
1540 return "Exactly 2 selected strips with video content are needed";
1541 }
1542 if (num_inputs == 1 && inputs.size() != 1) {
1543 return "Exactly one selected strip with video content is needed";
1544 }
1545 return "";
1546}
1547
1549 int num_inputs,
1550 bool ignore_active)
1551{
1552 if (num_inputs == 0) {
1553 return {};
1554 }
1555
1556 Editing *ed = seq::editing_get(scene);
1557 blender::VectorSet<Strip *> selected_strips = seq::query_selected_strips(ed->current_strips());
1558 /* Ignore sound strips for now (avoids unnecessary errors when connected strips are
1559 * selected together, and the intent to operate on strips with video content is clear). */
1560 selected_strips.remove_if([&](Strip *strip) { return strip->type == STRIP_TYPE_SOUND_RAM; });
1561
1562 if (ignore_active) {
1563 /* If `ignore_active` is true, this function is being called from the reassign inputs
1564 * operator, meaning the active strip must be the effect strip to reassign. */
1565 Strip *active_strip = seq::select_active_get(scene);
1566 selected_strips.remove_if([&](Strip *strip) { return strip == active_strip; });
1567 }
1568
1569 if (selected_strips.size() > num_inputs) {
1571 for (int64_t i : IndexRange(num_inputs)) {
1572 inputs.add(selected_strips[i]);
1573 }
1574 return inputs;
1575 }
1576
1577 return selected_strips;
1578}
1579
1581{
1583 Strip *active_strip = seq::select_active_get(scene);
1584 const int num_inputs = seq::effect_get_num_inputs(active_strip->type);
1585
1586 if (num_inputs == 0) {
1587 BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: strip has no inputs");
1588 return OPERATOR_CANCELLED;
1589 }
1590
1591 VectorSet<Strip *> inputs = strip_effect_get_new_inputs(scene, num_inputs, true);
1592 StringRef error_msg = effect_inputs_validate(inputs, num_inputs);
1593
1594 if (!error_msg.is_empty()) {
1595 BKE_report(op->reports, RPT_ERROR, error_msg.data());
1596 return OPERATOR_CANCELLED;
1597 }
1598
1599 Strip *input1 = inputs[0];
1600 Strip *input2 = inputs.size() == 2 ? inputs[1] : nullptr;
1601
1602 /* Check if reassigning would create recursivity. */
1603 if (seq::relations_render_loop_check(input1, active_strip) ||
1604 seq::relations_render_loop_check(input2, active_strip))
1605 {
1606 BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: recursion detected");
1607 return OPERATOR_CANCELLED;
1608 }
1609
1610 active_strip->input1 = input1;
1611 active_strip->input2 = input2;
1612
1613 int old_start = active_strip->start;
1614
1615 /* Force time position update for reassigned effects.
1616 * TODO(Richard): This is because internally startdisp is still used, due to poor performance
1617 * of mapping effect range to inputs. This mapping could be cached though. */
1620
1621 Editing *ed = seq::editing_get(scene);
1622 ListBase *active_seqbase = seq::active_seqbase_get(ed);
1623 if (seq::transform_test_overlap(scene, active_seqbase, active_strip)) {
1624 seq::transform_seqbase_shuffle(active_seqbase, active_strip, scene);
1625 }
1626
1627 seq::relations_invalidate_cache(scene, active_strip);
1628 seq::offset_animdata(scene, active_strip, (active_strip->start - old_start));
1629
1631
1632 return OPERATOR_FINISHED;
1633}
1634
1636{
1637 /* Identifiers. */
1638 ot->name = "Reassign Inputs";
1639 ot->idname = "SEQUENCER_OT_reassign_inputs";
1640 ot->description = "Reassign the inputs for the effect strip";
1641
1642 /* API callbacks. */
1644 ot->poll = sequencer_effect_poll;
1645
1646 /* Flags. */
1647 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1648}
1649
1651
1652/* -------------------------------------------------------------------- */
1655
1657{
1659 Strip *active_strip = seq::select_active_get(scene);
1660
1661 if (!active_strip->is_effect()) {
1662 BKE_report(op->reports, RPT_ERROR, "Active strip is not an effect strip");
1663 return OPERATOR_CANCELLED;
1664 }
1665
1666 if (seq::effect_get_num_inputs(active_strip->type) != 2 || active_strip->input1 == nullptr ||
1667 active_strip->input2 == nullptr)
1668 {
1669 BKE_report(op->reports, RPT_ERROR, "Strip needs two inputs to swap");
1670 return OPERATOR_CANCELLED;
1671 }
1672
1673 Strip *strip = active_strip->input1;
1674 active_strip->input1 = active_strip->input2;
1675 active_strip->input2 = strip;
1676
1677 seq::relations_invalidate_cache(scene, active_strip);
1679
1680 return OPERATOR_FINISHED;
1681}
1683{
1684 /* Identifiers. */
1685 ot->name = "Swap Inputs";
1686 ot->idname = "SEQUENCER_OT_swap_inputs";
1687 ot->description = "Swap the two inputs of the effect strip";
1688
1689 /* API callbacks. */
1692
1693 /* Flags. */
1694 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1695}
1696
1698
1699/* -------------------------------------------------------------------- */
1702
1703static int mouse_frame_side(View2D *v2d, short mouse_x, int frame)
1704{
1705 int mval[2];
1706 float mouseloc[2];
1707
1708 mval[0] = mouse_x;
1709 mval[1] = 0;
1710
1711 /* Choose the side based on which side of the current frame the mouse is on. */
1712 UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseloc[0], &mouseloc[1]);
1713
1714 return mouseloc[0] > frame ? seq::SIDE_RIGHT : seq::SIDE_LEFT;
1715}
1716
1718 {seq::SPLIT_SOFT, "SOFT", 0, "Soft", ""},
1719 {seq::SPLIT_HARD, "HARD", 0, "Hard", ""},
1720 {0, nullptr, 0, nullptr, nullptr},
1721};
1722
1724 {seq::SIDE_MOUSE, "MOUSE", 0, "Mouse Position", ""},
1725 {seq::SIDE_LEFT, "LEFT", 0, "Left", ""},
1726 {seq::SIDE_RIGHT, "RIGHT", 0, "Right", ""},
1727 {seq::SIDE_BOTH, "BOTH", 0, "Both", ""},
1728 {seq::SIDE_NO_CHANGE, "NO_CHANGE", 0, "No Change", ""},
1729 {0, nullptr, 0, nullptr, nullptr},
1730};
1731
1732/* Get the splitting side for the Split Strips's operator exec() callback. */
1734{
1735 const int split_side = RNA_enum_get(op->ptr, "side");
1736
1737 /* The mouse position can not be resolved from the exec() as the mouse coordinate is not
1738 * accessible. So fall-back to the RIGHT side instead.
1739 *
1740 * The SEQ_SIDE_MOUSE is used by the Strip menu, together with the EXEC_DEFAULT operator
1741 * context in order to have properly resolved shortcut in the menu. */
1742 if (split_side == seq::SIDE_MOUSE) {
1743 return seq::SIDE_RIGHT;
1744 }
1745
1746 return split_side;
1747}
1748
1750{
1751 Main *bmain = CTX_data_main(C);
1753 Editing *ed = seq::editing_get(scene);
1754 bool changed = false;
1755 bool strip_selected = false;
1756
1757 const bool use_cursor_position = RNA_boolean_get(op->ptr, "use_cursor_position");
1758
1759 const int split_frame = RNA_struct_property_is_set(op->ptr, "frame") ?
1760 RNA_int_get(op->ptr, "frame") :
1761 scene->r.cfra;
1762 const int split_channel = RNA_int_get(op->ptr, "channel");
1763
1764 const seq::eSplitMethod method = seq::eSplitMethod(RNA_enum_get(op->ptr, "type"));
1765 const int split_side = sequence_split_side_for_exec_get(op);
1766 const bool ignore_selection = RNA_boolean_get(op->ptr, "ignore_selection");
1767 const bool ignore_connections = RNA_boolean_get(op->ptr, "ignore_connections");
1768
1769 seq::prefetch_stop(scene);
1770
1771 LISTBASE_FOREACH_BACKWARD (Strip *, strip, ed->current_strips()) {
1772 if (use_cursor_position && strip->channel != split_channel) {
1773 continue;
1774 }
1775
1776 if (ignore_selection || strip->flag & SELECT) {
1777 const char *error_msg = nullptr;
1778 if (seq::edit_strip_split(bmain,
1779 scene,
1780 ed->current_strips(),
1781 strip,
1782 split_frame,
1783 method,
1784 ignore_connections,
1785 &error_msg) != nullptr)
1786 {
1787 changed = true;
1788 }
1789 if (error_msg != nullptr) {
1790 BKE_report(op->reports, RPT_ERROR, error_msg);
1791 }
1792 }
1793 }
1794
1795 if (changed) { /* Got new strips? */
1796 if (ignore_selection) {
1797 if (use_cursor_position) {
1799 if (seq::time_right_handle_frame_get(scene, strip) == split_frame &&
1800 strip->channel == split_channel)
1801 {
1802 strip_selected = strip->flag & STRIP_ALLSEL;
1803 }
1804 }
1805 if (!strip_selected) {
1807 if (seq::time_left_handle_frame_get(scene, strip) == split_frame &&
1808 strip->channel == split_channel)
1809 {
1810 strip->flag &= ~STRIP_ALLSEL;
1811 }
1812 }
1813 }
1814 }
1815 }
1816 else {
1817 if (split_side != seq::SIDE_BOTH) {
1819 if (split_side == seq::SIDE_LEFT) {
1820 if (seq::time_left_handle_frame_get(scene, strip) >= split_frame) {
1821 strip->flag &= ~STRIP_ALLSEL;
1822 }
1823 }
1824 else {
1825 if (seq::time_right_handle_frame_get(scene, strip) <= split_frame) {
1826 strip->flag &= ~STRIP_ALLSEL;
1827 }
1828 }
1829 }
1830 }
1831 }
1832 }
1833 if (changed) {
1835 return OPERATOR_FINISHED;
1836 }
1837
1838 /* Passthrough to selection if used as tool. */
1840}
1841
1843{
1846
1847 int split_side = RNA_enum_get(op->ptr, "side");
1848 int split_frame = scene->r.cfra;
1849
1850 if (split_side == seq::SIDE_MOUSE) {
1851 if (ED_operator_sequencer_active(C) && v2d) {
1852 split_side = mouse_frame_side(v2d, event->mval[0], split_frame);
1853 }
1854 else {
1855 split_side = seq::SIDE_BOTH;
1856 }
1857 }
1858 float mouseloc[2];
1859 if (v2d) {
1860 UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &mouseloc[0], &mouseloc[1]);
1861 if (RNA_boolean_get(op->ptr, "use_cursor_position")) {
1862 split_frame = round_fl_to_int(mouseloc[0]);
1863 Strip *strip = strip_under_mouse_get(scene, v2d, event->mval);
1864 if (strip == nullptr || split_frame == seq::time_left_handle_frame_get(scene, strip) ||
1865 split_frame == seq::time_right_handle_frame_get(scene, strip))
1866 {
1867 /* Do not pass through to selection. */
1868 return OPERATOR_CANCELLED;
1869 }
1870 }
1871 RNA_int_set(op->ptr, "channel", mouseloc[1]);
1872 }
1873 RNA_int_set(op->ptr, "frame", split_frame);
1874 RNA_enum_set(op->ptr, "side", split_side);
1875 // RNA_enum_set(op->ptr, "type", split_hard);
1876
1877 return sequencer_split_exec(C, op);
1878}
1879
1880static void sequencer_split_ui(bContext * /*C*/, wmOperator *op)
1881{
1882 uiLayout *layout = op->layout;
1883 layout->use_property_split_set(true);
1884 layout->use_property_decorate_set(false);
1885
1886 uiLayout *row = &layout->row(false);
1887 row->prop(op->ptr, "type", UI_ITEM_R_EXPAND, std::nullopt, ICON_NONE);
1888 layout->prop(op->ptr, "frame", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1889 layout->prop(op->ptr, "side", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1890
1891 layout->separator();
1892
1893 layout->prop(op->ptr, "use_cursor_position", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1894 if (RNA_boolean_get(op->ptr, "use_cursor_position")) {
1895 layout->prop(op->ptr, "channel", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1896 }
1897
1898 layout->separator();
1899
1900 layout->prop(op->ptr, "ignore_connections", UI_ITEM_NONE, std::nullopt, ICON_NONE);
1901}
1902
1904{
1905 /* Identifiers. */
1906 ot->name = "Split Strips";
1907 ot->idname = "SEQUENCER_OT_split";
1908 ot->description = "Split the selected strips in two";
1909
1910 /* API callbacks. */
1911 ot->invoke = sequencer_split_invoke;
1912 ot->exec = sequencer_split_exec;
1913 ot->poll = sequencer_edit_poll;
1914 ot->ui = sequencer_split_ui;
1915
1916 /* Flags. */
1917 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1918
1919 PropertyRNA *prop;
1920 RNA_def_int(ot->srna,
1921 "frame",
1922 0,
1923 INT_MIN,
1924 INT_MAX,
1925 "Frame",
1926 "Frame where selected strips will be split",
1927 INT_MIN,
1928 INT_MAX);
1929 RNA_def_int(ot->srna,
1930 "channel",
1931 0,
1932 INT_MIN,
1933 INT_MAX,
1934 "Channel",
1935 "Channel in which strip will be cut",
1936 INT_MIN,
1937 INT_MAX);
1938 RNA_def_enum(ot->srna,
1939 "type",
1942 "Type",
1943 "The type of split operation to perform on strips");
1944
1945 RNA_def_boolean(ot->srna,
1946 "use_cursor_position",
1947 false,
1948 "Use Cursor Position",
1949 "Split at position of the cursor instead of current frame");
1950
1951 prop = RNA_def_enum(ot->srna,
1952 "side",
1955 "Side",
1956 "The side that remains selected after splitting");
1957
1959
1960 prop = RNA_def_boolean(
1961 ot->srna,
1962 "ignore_selection",
1963 false,
1964 "Ignore Selection",
1965 "Make cut even if strip is not selected preserving selection state after cut");
1966
1968
1969 RNA_def_boolean(ot->srna,
1970 "ignore_connections",
1971 false,
1972 "Ignore Connections",
1973 "Don't propagate split to connected strips");
1974}
1975
1977
1978/* -------------------------------------------------------------------- */
1981
1982static void sequencer_report_duplicates(wmOperator *op, ListBase *duplicated_strips)
1983{
1984 blender::Set<Scene *> scenes;
1985 blender::Set<MovieClip *> movieclips;
1987
1988 LISTBASE_FOREACH (Strip *, strip, duplicated_strips) {
1989 switch (strip->type) {
1990 case STRIP_TYPE_SCENE:
1991 if (strip->scene) {
1992 scenes.add(strip->scene);
1993 }
1994 break;
1996 if (strip->clip) {
1997 movieclips.add(strip->clip);
1998 }
1999 break;
2000 case STRIP_TYPE_MASK:
2001 if (strip->mask) {
2002 masks.add(strip->mask);
2003 }
2004 break;
2005 default:
2006 break;
2007 }
2008 }
2009
2010 const int num_scenes = scenes.size();
2011 const int num_movieclips = movieclips.size();
2012 const int num_masks = masks.size();
2013
2014 if (num_scenes == 0 && num_movieclips == 0 && num_masks == 0) {
2015 return;
2016 }
2017
2018 std::string report;
2019 std::string sep;
2020 if (num_scenes) {
2021 report += fmt::format("{}{} {}",
2022 sep,
2023 num_scenes,
2024 (num_scenes > 1) ? RPT_(BKE_idtype_idcode_to_name_plural(ID_SCE)) :
2026 sep = ", ";
2027 }
2028 if (num_movieclips) {
2029 report += fmt::format("{}{} {}",
2030 sep,
2031 num_movieclips,
2032 (num_movieclips > 1) ? RPT_(BKE_idtype_idcode_to_name_plural(ID_MC)) :
2034 sep = ", ";
2035 }
2036 if (num_masks) {
2037 report += fmt::format("{}{} {}",
2038 sep,
2039 num_masks,
2040 (num_masks > 1) ? RPT_(BKE_idtype_idcode_to_name_plural(ID_MSK)) :
2042 sep = ", ";
2043 }
2044
2045 BKE_reportf(op->reports, RPT_INFO, RPT_("Duplicated %s"), report.c_str());
2046}
2047
2049{
2050 Main *bmain = CTX_data_main(C);
2052 Editing *ed = seq::editing_get(scene);
2053 ARegion *region = CTX_wm_region(C);
2054
2055 const bool linked = RNA_boolean_get(op->ptr, "linked");
2056
2057 if (ed == nullptr) {
2058 return OPERATOR_CANCELLED;
2059 }
2060
2061 Strip *active_strip = seq::select_active_get(scene);
2062 ListBase duplicated_strips = {nullptr, nullptr};
2063
2064 /* Special case for duplicating strips in preview: Do not duplicate sound strips,muted
2065 * strips and strips that do not intersect the current frame */
2067 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
2068 if (strip->type == STRIP_TYPE_SOUND_RAM || strip->flag & SEQ_MUTE ||
2069 !seq::time_strip_intersects_frame(scene, strip, scene->r.cfra))
2070 {
2071 strip->flag &= ~STRIP_ALLSEL;
2072 }
2073 }
2074 }
2075
2076 const seq::StripDuplicate dupe_flag = linked ? seq::StripDuplicate::Selected :
2080 bmain, scene, scene, &duplicated_strips, ed->current_strips(), dupe_flag, 0);
2081 deselect_all_strips(scene);
2082
2083 if (duplicated_strips.first == nullptr) {
2084 return OPERATOR_CANCELLED;
2085 }
2086
2087 /* Report all the newly created datablocks in the status bar. */
2088 if (!linked) {
2089 sequencer_report_duplicates(op, &duplicated_strips);
2090 }
2091
2092 /* Duplicate animation.
2093 * First backup original curves from scene and duplicate strip curves from backup into scene.
2094 * This way, when pasted strips are renamed, curves are renamed with them. Finally, restore
2095 * original curves from backup.
2096 */
2097 seq::AnimationBackup animation_backup = {{nullptr}};
2098 seq::animation_backup_original(scene, &animation_backup);
2099
2101 Strip *strip_last = static_cast<Strip *>(seqbase->last);
2102
2103 /* Rely on the `duplicated_strips` list being added at the end.
2104 * Their UIDs has been re-generated by the #SEQ_sequence_base_dupli_recursive(). */
2105 BLI_movelisttolist(ed->current_strips(), &duplicated_strips);
2106
2107 /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation
2108 * data. */
2109 for (Strip *strip = strip_last->next; strip; strip = strip->next) {
2110 if (active_strip != nullptr && STREQ(strip->name, active_strip->name)) {
2111 seq::select_active_set(scene, strip);
2112 }
2113 strip->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK);
2114 strip->runtime.flag |= STRIP_IGNORE_CHANNEL_LOCK;
2115
2116 seq::animation_duplicate_backup_to_scene(scene, strip, &animation_backup);
2117 seq::ensure_unique_name(strip, scene);
2118 }
2119
2120 /* Special case for duplicating strips in preview: handle overlap, because strips won't be
2121 * translated. */
2123 for (Strip *strip = strip_last->next; strip; strip = strip->next) {
2124 if (seq::transform_test_overlap(scene, ed->current_strips(), strip)) {
2125 seq::transform_seqbase_shuffle(ed->current_strips(), strip, scene);
2126 }
2127 strip->runtime.flag &= ~STRIP_IGNORE_CHANNEL_LOCK;
2128 }
2129 }
2130
2131 seq::animation_restore_original(scene, &animation_backup);
2132
2136 return OPERATOR_FINISHED;
2137}
2138
2140{
2141 PropertyRNA *prop;
2142
2143 /* Identifiers. */
2144 ot->name = "Duplicate Strips";
2145 ot->idname = "SEQUENCER_OT_duplicate";
2146 ot->description = "Duplicate the selected strips";
2147
2148 /* API callbacks. */
2151
2152 /* Flags. */
2153 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2154
2155 prop = RNA_def_boolean(ot->srna,
2156 "linked",
2157 false,
2158 "Linked",
2159 "Duplicate strip but not strip data, linking to the original data");
2161}
2162
2164
2165/* -------------------------------------------------------------------- */
2168
2170{
2171 if (strip->type != STRIP_TYPE_SCENE) {
2172 return;
2173 }
2174
2175 Main *bmain = CTX_data_main(C);
2176 if (strip->scene) {
2177 if (ED_scene_delete(C, bmain, strip->scene)) {
2179 }
2180 }
2181}
2182
2184{
2185 Main *bmain = CTX_data_main(C);
2188 const bool delete_data = RNA_boolean_get(op->ptr, "delete_data");
2189
2191 return OPERATOR_CANCELLED;
2192 }
2193
2194 seq::prefetch_stop(scene);
2195
2196 for (Strip *strip : selected_strips_from_context(C)) {
2197 seq::edit_flag_for_removal(scene, seqbasep, strip);
2198 if (delete_data) {
2200 }
2201 }
2202 seq::edit_remove_flagged_strips(scene, seqbasep);
2203
2205 if (scene->adt && scene->adt->action) {
2207 }
2211 return OPERATOR_FINISHED;
2212}
2213
2215{
2217 ListBase *markers = &scene->markers;
2218
2219 if (!BLI_listbase_is_empty(markers)) {
2220 ARegion *region = CTX_wm_region(C);
2221 if (region && (region->regiontype == RGN_TYPE_WINDOW)) {
2222 /* Bounding box of 30 pixels is used for markers shortcuts,
2223 * prevent conflict with markers shortcuts here. */
2224 if (event->mval[1] <= 30) {
2225 return OPERATOR_PASS_THROUGH;
2226 }
2227 }
2228 }
2229
2230 return sequencer_delete_exec(C, op);
2231}
2232
2234{
2235 /* Identifiers. */
2236 ot->name = "Delete Strips";
2237 ot->idname = "SEQUENCER_OT_delete";
2238 ot->description = "Delete selected strips from the sequencer";
2239
2240 /* API callbacks. */
2241 ot->invoke = sequencer_delete_invoke;
2242 ot->exec = sequencer_delete_exec;
2243 ot->poll = sequencer_edit_poll;
2244
2245 /* Flags. */
2246 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2247
2248 /* Properties. */
2249 ot->prop = RNA_def_boolean(ot->srna,
2250 "delete_data",
2251 false,
2252 "Delete Data",
2253 "After removing the Strip, delete the associated data also");
2255}
2256
2258
2259/* -------------------------------------------------------------------- */
2262
2264{
2266 Editing *ed = seq::editing_get(scene);
2267 Strip *strip;
2269
2270 /* For effects, try to find a replacement input. */
2271 for (strip = static_cast<Strip *>(ed->current_strips()->first); strip;
2272 strip = static_cast<Strip *>(strip->next))
2273 {
2274 if (seq::transform_is_locked(channels, strip)) {
2275 continue;
2276 }
2277
2278 if (!strip->is_effect() && (strip->flag & SELECT)) {
2279 strip->startofs = strip->endofs = 0;
2280 }
2281 }
2282
2283 /* Update lengths, etc. */
2284 strip = static_cast<Strip *>(ed->current_strips()->first);
2285 while (strip) {
2286 seq::relations_invalidate_cache(scene, strip);
2287 strip = strip->next;
2288 }
2289
2290 for (strip = static_cast<Strip *>(ed->current_strips()->first); strip;
2291 strip = static_cast<Strip *>(strip->next))
2292 {
2293 if (!strip->is_effect() && (strip->flag & SELECT)) {
2294 if (seq::transform_test_overlap(scene, ed->current_strips(), strip)) {
2295 seq::transform_seqbase_shuffle(ed->current_strips(), strip, scene);
2296 }
2297 }
2298 }
2299
2301
2302 return OPERATOR_FINISHED;
2303}
2304
2306{
2307 /* Identifiers. */
2308 ot->name = "Clear Strip Offset";
2309 ot->idname = "SEQUENCER_OT_offset_clear";
2310 ot->description = "Clear strip in/out offsets from the start and end of content";
2311
2312 /* API callbacks. */
2314 ot->poll = sequencer_edit_poll;
2315
2316 /* Flags. */
2317 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2318}
2319
2321
2322/* -------------------------------------------------------------------- */
2325
2327{
2328 Main *bmain = CTX_data_main(C);
2330 Editing *ed = seq::editing_get(scene);
2332
2333 Strip *strip, *strip_new;
2334 StripData *data_new;
2335 StripElem *se, *se_new;
2336 int start_ofs, timeline_frame, frame_end;
2337 int step = RNA_int_get(op->ptr, "length");
2338
2339 strip = static_cast<Strip *>(seqbase->first); /* Poll checks this is valid. */
2340
2341 seq::prefetch_stop(scene);
2342
2343 while (strip) {
2344 if ((strip->flag & SELECT) && (strip->type == STRIP_TYPE_IMAGE) && (strip->len > 1)) {
2345 Strip *strip_next;
2346
2347 /* TODO: remove f-curve and assign to split image strips.
2348 * The old animation system would remove the user of `strip->ipo_legacy`. */
2349
2350 start_ofs = timeline_frame = seq::time_left_handle_frame_get(scene, strip);
2351 frame_end = seq::time_right_handle_frame_get(scene, strip);
2352
2353 while (timeline_frame < frame_end) {
2354 /* New strip. */
2355 se = seq::render_give_stripelem(scene, strip, timeline_frame);
2356
2358 bmain, scene, scene, seqbase, strip, seq::StripDuplicate::UniqueName);
2359
2360 strip_new->start = start_ofs;
2361 strip_new->type = STRIP_TYPE_IMAGE;
2362 strip_new->len = 1;
2363 strip_new->flag |= SEQ_SINGLE_FRAME_CONTENT;
2364 strip_new->endofs = 1 - step;
2365
2366 /* New strip. */
2367 data_new = strip_new->data;
2368 data_new->us = 1;
2369
2370 /* New stripdata, only one element now. */
2371 /* Note this assume all elements (images) have the same dimension,
2372 * since we only copy the name here. */
2373 se_new = static_cast<StripElem *>(MEM_reallocN(data_new->stripdata, sizeof(*se_new)));
2374 STRNCPY_UTF8(se_new->filename, se->filename);
2375 data_new->stripdata = se_new;
2376
2377 if (step > 1) {
2378 strip_new->runtime.flag &= ~STRIP_OVERLAP;
2379 if (seq::transform_test_overlap(scene, seqbase, strip_new)) {
2380 seq::transform_seqbase_shuffle(seqbase, strip_new, scene);
2381 }
2382 }
2383
2384 /* XXX, COPY FCURVES */
2385
2386 timeline_frame++;
2387 start_ofs += step;
2388 }
2389
2390 strip_next = static_cast<Strip *>(strip->next);
2391 seq::edit_flag_for_removal(scene, seqbase, strip);
2392 strip = strip_next;
2393 }
2394 else {
2395 strip = strip->next;
2396 }
2397 }
2398
2399 seq::edit_remove_flagged_strips(scene, seqbase);
2401
2402 return OPERATOR_FINISHED;
2403}
2404
2406 wmOperator *op,
2407 const wmEvent *event)
2408{
2410 C, op, event, IFACE_("Separate Sequence Images"), IFACE_("Separate"));
2411}
2412
2414{
2415 /* Identifiers. */
2416 ot->name = "Separate Images";
2417 ot->idname = "SEQUENCER_OT_images_separate";
2418 ot->description = "On image sequence strips, it returns a strip for each image";
2419
2420 /* API callbacks. */
2423 ot->poll = sequencer_edit_poll;
2424
2425 /* Flags. */
2426 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2427
2428 RNA_def_int(ot->srna, "length", 1, 1, INT_MAX, "Length", "Length of each frame", 1, 1000);
2429}
2430
2432
2433/* -------------------------------------------------------------------- */
2436
2438{
2440 Editing *ed = seq::editing_get(scene);
2441 Strip *active_strip = seq::select_active_get(scene);
2442
2443 seq::prefetch_stop(scene);
2444
2445 if (active_strip && active_strip->type == STRIP_TYPE_META && active_strip->flag & SELECT) {
2446 /* Deselect active meta strip. */
2447 seq::select_active_set(scene, nullptr);
2448 seq::meta_stack_set(scene, active_strip);
2449 /* Invalidate the cache of the meta strip when going in and out of it.
2450 * The cache does not consider if we are inside of a meta strip or not,
2451 * so we have to make sure that we recache so it is not using outdated data.
2452 */
2453 seq::relations_invalidate_cache(scene, active_strip);
2454 }
2455 else {
2456 /* Exit meta-strip if possible. */
2457 if (BLI_listbase_is_empty(&ed->metastack)) {
2458 return OPERATOR_CANCELLED;
2459 }
2460
2461 /* Display parent meta. */
2462 Strip *meta_parent = seq::meta_stack_pop(ed);
2463 seq::select_active_set(scene, meta_parent);
2464 /* Invalidate the cache of the meta strip when going in and out of it.
2465 * The cache does not consider if we are inside of a meta strip or not,
2466 * so we have to make sure that we recache so it is not using outdated data.
2467 */
2468 seq::relations_invalidate_cache(scene, meta_parent);
2469 }
2470
2473
2474 return OPERATOR_FINISHED;
2475}
2476
2478{
2479 /* Identifiers. */
2480 ot->name = "Toggle Meta Strip";
2481 ot->idname = "SEQUENCER_OT_meta_toggle";
2482 ot->description = "Toggle a meta-strip (to edit enclosed strips)";
2483
2484 /* API callbacks. */
2486 ot->poll = sequencer_edit_poll;
2487
2488 /* Flags. */
2489 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2490}
2491
2493
2494/* -------------------------------------------------------------------- */
2497
2499{
2501 Editing *ed = seq::editing_get(scene);
2502 Strip *active_strip = seq::select_active_get(scene);
2503 ListBase *active_seqbase = seq::active_seqbase_get(ed);
2504
2506
2507 if (selected.is_empty()) {
2508 return OPERATOR_CANCELLED;
2509 }
2510
2511 seq::prefetch_stop(scene);
2512
2513 int channel_max = 1, channel_min = std::numeric_limits<int>::max(), meta_start_frame = MAXFRAME,
2514 meta_end_frame = std::numeric_limits<int>::min();
2515 Strip *strip_meta = seq::strip_alloc(active_seqbase, 1, 1, STRIP_TYPE_META);
2516
2517 /* Remove all selected from main list, and put in meta.
2518 * Strip is moved within the same edit, no need to re-generate the UID. */
2519 blender::VectorSet<Strip *> strips_to_move;
2520 strips_to_move.add_multiple(selected);
2522 scene, active_seqbase, strips_to_move, seq::query_strip_connected_and_effect_chain);
2523
2524 for (Strip *strip : strips_to_move) {
2525 seq::relations_invalidate_cache(scene, strip);
2526 BLI_remlink(active_seqbase, strip);
2527 BLI_addtail(&strip_meta->seqbase, strip);
2528 channel_max = max_ii(strip->channel, channel_max);
2529 channel_min = min_ii(strip->channel, channel_min);
2530 meta_start_frame = min_ii(seq::time_left_handle_frame_get(scene, strip), meta_start_frame);
2531 meta_end_frame = max_ii(seq::time_right_handle_frame_get(scene, strip), meta_end_frame);
2532 }
2533
2534 ListBase *channels_cur = seq::channels_displayed_get(ed);
2535 ListBase *channels_meta = &strip_meta->channels;
2536 for (int i = channel_min; i <= channel_max; i++) {
2537 SeqTimelineChannel *channel_cur = seq::channel_get_by_index(channels_cur, i);
2538 SeqTimelineChannel *channel_meta = seq::channel_get_by_index(channels_meta, i);
2539 STRNCPY_UTF8(channel_meta->name, channel_cur->name);
2540 channel_meta->flag = channel_cur->flag;
2541 }
2542
2543 const int channel = active_strip ? active_strip->channel : channel_max;
2544 seq::strip_channel_set(strip_meta, channel);
2545 BLI_strncpy_utf8(strip_meta->name + 2, DATA_("MetaStrip"), sizeof(strip_meta->name) - 2);
2546 seq::strip_unique_name_set(scene, &ed->seqbase, strip_meta);
2547 strip_meta->start = meta_start_frame;
2548 strip_meta->len = meta_end_frame - meta_start_frame;
2549 seq::select_active_set(scene, strip_meta);
2550 if (seq::transform_test_overlap(scene, active_seqbase, strip_meta)) {
2551 seq::transform_seqbase_shuffle(active_seqbase, strip_meta, scene);
2552 }
2553
2557
2558 return OPERATOR_FINISHED;
2559}
2560
2562{
2563 /* Identifiers. */
2564 ot->name = "Make Meta Strip";
2565 ot->idname = "SEQUENCER_OT_meta_make";
2566 ot->description = "Group selected strips into a meta-strip";
2567
2568 /* API callbacks. */
2570 ot->poll = sequencer_edit_poll;
2571
2572 /* Flags. */
2573 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2574}
2575
2577
2578/* -------------------------------------------------------------------- */
2581
2583{
2585 Editing *ed = seq::editing_get(scene);
2586 Strip *active_strip = seq::select_active_get(scene);
2587
2588 if (active_strip == nullptr || active_strip->type != STRIP_TYPE_META) {
2589 return OPERATOR_CANCELLED;
2590 }
2591
2592 seq::prefetch_stop(scene);
2593
2594 LISTBASE_FOREACH (Strip *, strip, &active_strip->seqbase) {
2595 seq::relations_invalidate_cache(scene, strip);
2596 }
2597
2598 /* Remove all selected from meta, and put in main list.
2599 * Strip is moved within the same edit, no need to re-generate the UID. */
2600 BLI_movelisttolist(ed->current_strips(), &active_strip->seqbase);
2601 BLI_listbase_clear(&active_strip->seqbase);
2602
2603 ListBase *active_seqbase = seq::active_seqbase_get(ed);
2604 seq::edit_flag_for_removal(scene, active_seqbase, active_strip);
2605 seq::edit_remove_flagged_strips(scene, active_seqbase);
2606
2607 /* Test for effects and overlap. */
2608 LISTBASE_FOREACH (Strip *, strip, active_seqbase) {
2609 if (strip->flag & SELECT) {
2610 strip->runtime.flag &= ~STRIP_OVERLAP;
2611 if (seq::transform_test_overlap(scene, active_seqbase, strip)) {
2612 seq::transform_seqbase_shuffle(active_seqbase, strip, scene);
2613 }
2614 }
2615 }
2616
2619
2620 return OPERATOR_FINISHED;
2621}
2622
2624{
2625 /* Identifiers. */
2626 ot->name = "UnMeta Strip";
2627 ot->idname = "SEQUENCER_OT_meta_separate";
2628 ot->description = "Put the contents of a meta-strip back in the sequencer";
2629
2630 /* API callbacks. */
2632 ot->poll = sequencer_edit_poll;
2633
2634 /* Flags. */
2635 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2636}
2637
2639
2640/* -------------------------------------------------------------------- */
2643
2644static bool strip_jump_internal(Scene *scene,
2645 const short side,
2646 const bool do_skip_mute,
2647 const bool do_center)
2648{
2649 bool changed = false;
2650 int timeline_frame = scene->r.cfra;
2651 int next_frame = seq::time_find_next_prev_edit(
2652 scene, timeline_frame, side, do_skip_mute, do_center, false);
2653
2654 if (next_frame != timeline_frame) {
2655 scene->r.cfra = next_frame;
2656 changed = true;
2657 }
2658
2659 return changed;
2660}
2661
2663{
2664 /* Prevent changes during render. */
2665 if (G.is_rendering) {
2666 return false;
2667 }
2668
2669 return sequencer_edit_poll(C);
2670}
2671
2673{
2675 const bool next = RNA_boolean_get(op->ptr, "next");
2676 const bool center = RNA_boolean_get(op->ptr, "center");
2677
2678 /* Currently do_skip_mute is always true. */
2679 if (!strip_jump_internal(scene, next ? seq::SIDE_RIGHT : seq::SIDE_LEFT, true, center)) {
2680 return OPERATOR_CANCELLED;
2681 }
2682
2685
2686 return OPERATOR_FINISHED;
2687}
2688
2690{
2691 /* Identifiers. */
2692 ot->name = "Jump to Strip";
2693 ot->idname = "SEQUENCER_OT_strip_jump";
2694 ot->description = "Move frame to previous edit point";
2695
2696 /* API callbacks. */
2699
2700 /* Flags. */
2701 ot->flag = OPTYPE_UNDO;
2702
2703 /* Properties. */
2704 RNA_def_boolean(ot->srna, "next", true, "Next Strip", "");
2705 RNA_def_boolean(ot->srna, "center", true, "Use Strip Center", "");
2706}
2707
2709
2710/* -------------------------------------------------------------------- */
2713
2715 {seq::SIDE_LEFT, "LEFT", 0, "Left", ""},
2716 {seq::SIDE_RIGHT, "RIGHT", 0, "Right", ""},
2717 {0, nullptr, 0, nullptr, nullptr},
2718};
2719
2720static void swap_strips(Scene *scene, Strip *strip_a, Strip *strip_b)
2721{
2722 int gap = seq::time_left_handle_frame_get(scene, strip_b) -
2723 seq::time_right_handle_frame_get(scene, strip_a);
2724 int strip_a_start;
2725 int strip_b_start;
2726
2727 strip_b_start = (strip_b->start - seq::time_left_handle_frame_get(scene, strip_b)) +
2728 seq::time_left_handle_frame_get(scene, strip_a);
2729 seq::transform_translate_strip(scene, strip_b, strip_b_start - strip_b->start);
2730 seq::relations_invalidate_cache(scene, strip_b);
2731
2732 strip_a_start = (strip_a->start - seq::time_left_handle_frame_get(scene, strip_a)) +
2733 seq::time_right_handle_frame_get(scene, strip_b) + gap;
2734 seq::transform_translate_strip(scene, strip_a, strip_a_start - strip_a->start);
2735 seq::relations_invalidate_cache(scene, strip_a);
2736}
2737
2738static Strip *find_next_prev_strip(Scene *scene, Strip *test, int lr, int sel)
2739{
2740 /* sel: 0==unselected, 1==selected, -1==don't care. */
2741 Strip *strip, *best_strip = nullptr;
2742 Editing *ed = seq::editing_get(scene);
2743
2744 int dist, best_dist;
2745 best_dist = MAXFRAME * 2;
2746
2747 if (ed == nullptr) {
2748 return nullptr;
2749 }
2750
2751 strip = static_cast<Strip *>(ed->current_strips()->first);
2752 while (strip) {
2753 if ((strip != test) && (test->channel == strip->channel) &&
2754 ((sel == -1) || (sel == (strip->flag & SELECT))))
2755 {
2756 dist = MAXFRAME * 2;
2757
2758 switch (lr) {
2759 case seq::SIDE_LEFT:
2760 if (seq::time_right_handle_frame_get(scene, strip) <=
2762 {
2763 dist = seq::time_right_handle_frame_get(scene, test) -
2764 seq::time_left_handle_frame_get(scene, strip);
2765 }
2766 break;
2767 case seq::SIDE_RIGHT:
2768 if (seq::time_left_handle_frame_get(scene, strip) >=
2770 {
2771 dist = seq::time_left_handle_frame_get(scene, strip) -
2773 }
2774 break;
2775 }
2776
2777 if (dist == 0) {
2778 best_strip = strip;
2779 break;
2780 }
2781 if (dist < best_dist) {
2782 best_dist = dist;
2783 best_strip = strip;
2784 }
2785 }
2786 strip = static_cast<Strip *>(strip->next);
2787 }
2788 return best_strip; /* Can be nullptr. */
2789}
2790
2791static bool strip_is_parent(const Strip *par, const Strip *strip)
2792{
2793 return ((par->input1 == strip) || (par->input2 == strip));
2794}
2795
2797{
2799 Editing *ed = seq::editing_get(scene);
2800 Strip *active_strip = seq::select_active_get(scene);
2802 Strip *strip;
2803 int side = RNA_enum_get(op->ptr, "side");
2804
2805 if (active_strip == nullptr) {
2806 return OPERATOR_CANCELLED;
2807 }
2808
2809 strip = find_next_prev_strip(scene, active_strip, side, -1);
2810
2811 if (strip) {
2812
2813 /* Disallow effect strips. */
2814 if (seq::effect_get_num_inputs(strip->type) >= 1 &&
2815 (strip->effectdata || strip->input1 || strip->input2))
2816 {
2817 return OPERATOR_CANCELLED;
2818 }
2819 if ((seq::effect_get_num_inputs(active_strip->type) >= 1) &&
2820 (active_strip->effectdata || active_strip->input1 || active_strip->input2))
2821 {
2822 return OPERATOR_CANCELLED;
2823 }
2824
2826 if (seq::transform_is_locked(channels, strip) ||
2827 seq::transform_is_locked(channels, active_strip))
2828 {
2829 return OPERATOR_CANCELLED;
2830 }
2831
2832 switch (side) {
2833 case seq::SIDE_LEFT:
2834 swap_strips(scene, strip, active_strip);
2835 break;
2836 case seq::SIDE_RIGHT:
2837 swap_strips(scene, active_strip, strip);
2838 break;
2839 }
2840
2841 /* Do this in a new loop since both effects need to be calculated first. */
2842 LISTBASE_FOREACH (Strip *, istrip, seqbase) {
2843 if (istrip->is_effect() &&
2844 (strip_is_parent(istrip, active_strip) || strip_is_parent(istrip, strip)))
2845 {
2846 /* This may now overlap. */
2847 if (seq::transform_test_overlap(scene, seqbase, istrip)) {
2848 seq::transform_seqbase_shuffle(seqbase, istrip, scene);
2849 }
2850 }
2851 }
2852
2854 return OPERATOR_FINISHED;
2855 }
2856
2857 return OPERATOR_CANCELLED;
2858}
2859
2861{
2862 /* Identifiers. */
2863 ot->name = "Swap Strip";
2864 ot->idname = "SEQUENCER_OT_swap";
2865 ot->description = "Swap active strip with strip to the right or left";
2866
2867 /* API callbacks. */
2868 ot->exec = sequencer_swap_exec;
2869 ot->poll = sequencer_edit_poll;
2870
2871 /* Flags. */
2872 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2873
2874 /* Properties. */
2876 ot->srna, "side", prop_side_lr_types, seq::SIDE_RIGHT, "Side", "Side of the strip to swap");
2877}
2878
2880
2881/* -------------------------------------------------------------------- */
2884
2886{
2888 Strip *active_strip = seq::select_active_get(scene);
2889 StripElem *se = nullptr;
2890
2891 if (active_strip == nullptr || active_strip->data == nullptr) {
2892 return OPERATOR_CANCELLED;
2893 }
2894
2895 switch (active_strip->type) {
2896 case STRIP_TYPE_IMAGE:
2897 se = seq::render_give_stripelem(scene, active_strip, scene->r.cfra);
2898 break;
2899 case STRIP_TYPE_MOVIE:
2900 se = active_strip->data->stripdata;
2901 break;
2902 default:
2903 return OPERATOR_CANCELLED;
2904 }
2905
2906 if (se == nullptr) {
2907 return OPERATOR_CANCELLED;
2908 }
2909
2910 /* Prevent setting the render size if values aren't initialized. */
2911 if (se->orig_width <= 0 || se->orig_height <= 0) {
2912 return OPERATOR_CANCELLED;
2913 }
2914
2915 scene->r.xsch = se->orig_width;
2916 scene->r.ysch = se->orig_height;
2917
2918 active_strip->data->transform->scale_x = active_strip->data->transform->scale_y = 1.0f;
2919 active_strip->data->transform->xofs = active_strip->data->transform->yofs = 0.0f;
2920
2921 seq::relations_invalidate_cache(scene, active_strip);
2924
2925 return OPERATOR_FINISHED;
2926}
2927
2929{
2930 /* Identifiers. */
2931 ot->name = "Set Render Size";
2932 ot->idname = "SEQUENCER_OT_rendersize";
2933 ot->description = "Set render size and aspect from active strip";
2934
2935 /* API callbacks. */
2937 ot->poll = sequencer_edit_poll;
2938
2939 /* Flags. */
2940 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2941}
2942
2944
2945/* -------------------------------------------------------------------- */
2948
2950{
2951 /* Identifiers. */
2952 ot->name = "Copy";
2953 ot->idname = "SEQUENCER_OT_copy";
2954 ot->description = "Copy the selected strips to the internal clipboard";
2955
2956 /* API callbacks. */
2958 ot->poll = sequencer_edit_poll;
2959
2960 /* Flags. */
2961 ot->flag = OPTYPE_REGISTER;
2962}
2963
2965
2966/* -------------------------------------------------------------------- */
2969
2971{
2972 /* Identifiers. */
2973 ot->name = "Paste";
2974 ot->idname = "SEQUENCER_OT_paste";
2975 ot->description = "Paste strips from the internal clipboard";
2976
2977 /* API callbacks. */
2981
2982 /* Flags. */
2983 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2984
2985 /* Properties. */
2987 ot->srna,
2988 "keep_offset",
2989 false,
2990 "Keep Offset",
2991 "Keep strip offset relative to the current frame when pasting");
2993 prop = RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2995 prop = RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2997}
2998
3000
3001/* -------------------------------------------------------------------- */
3004
3006{
3008 Strip *strip_act;
3009 Strip *strip_other;
3010 const char *error_msg;
3011
3012 if (seq::select_active_get_pair(scene, &strip_act, &strip_other) == false) {
3013 BKE_report(op->reports, RPT_ERROR, "Please select two strips");
3014 return OPERATOR_CANCELLED;
3015 }
3016
3017 if (seq::edit_strip_swap(scene, strip_act, strip_other, &error_msg) == false) {
3018 BKE_report(op->reports, RPT_ERROR, error_msg);
3019 return OPERATOR_CANCELLED;
3020 }
3021
3022 if (strip_act->scene_sound) {
3023 BKE_sound_remove_scene_sound(scene, strip_act->scene_sound);
3024 }
3025
3026 if (strip_other->scene_sound) {
3027 BKE_sound_remove_scene_sound(scene, strip_other->scene_sound);
3028 }
3029
3030 strip_act->scene_sound = nullptr;
3031 strip_other->scene_sound = nullptr;
3032
3033 if (strip_act->sound) {
3034 BKE_sound_add_scene_sound_defaults(scene, strip_act);
3035 }
3036 if (strip_other->sound) {
3037 BKE_sound_add_scene_sound_defaults(scene, strip_other);
3038 }
3039
3040 seq::relations_invalidate_cache_raw(scene, strip_act);
3041 seq::relations_invalidate_cache_raw(scene, strip_other);
3042
3044
3045 return OPERATOR_FINISHED;
3046}
3047
3049{
3050 /* Identifiers. */
3051 ot->name = "Sequencer Swap Data";
3052 ot->idname = "SEQUENCER_OT_swap_data";
3053 ot->description = "Swap 2 sequencer strips";
3054
3055 /* API callbacks. */
3058
3059 /* Flags. */
3060 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3061}
3062
3064
3065/* -------------------------------------------------------------------- */
3068
3070 {STRIP_TYPE_CROSS, "CROSS", 0, "Crossfade", "Fade out of one video, fading into another"},
3071 {STRIP_TYPE_ADD, "ADD", 0, "Add", "Add together color channels from two videos"},
3072 {STRIP_TYPE_SUB, "SUBTRACT", 0, "Subtract", "Subtract one strip's color from another"},
3073 {STRIP_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", "Blend alpha on top of another video"},
3074 {STRIP_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", "Blend alpha below another video"},
3075 {STRIP_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Crossfade", "Crossfade with color correction"},
3076 {STRIP_TYPE_MUL, "MULTIPLY", 0, "Multiply", "Multiply color channels from two videos"},
3077 {STRIP_TYPE_WIPE, "WIPE", 0, "Wipe", "Sweep a transition line across the frame"},
3078 {STRIP_TYPE_GLOW, "GLOW", 0, "Glow", "Add blur and brightness to light areas"},
3079 {STRIP_TYPE_COLOR, "COLOR", 0, "Color", "Add a simple color strip"},
3080 {STRIP_TYPE_SPEED, "SPEED", 0, "Speed", "Timewarp video strips, modifying playback speed"},
3081 {STRIP_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", "Control active camera angles"},
3082 {STRIP_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", "Apply nondestructive effects"},
3083 {STRIP_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", "Soften details along axes"},
3084 {STRIP_TYPE_TEXT, "TEXT", 0, "Text", "Add a simple text strip"},
3085 {STRIP_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", "Combine two strips using blend modes"},
3086 {0, nullptr, 0, nullptr, nullptr},
3087};
3088
3090{
3092 Strip *strip = seq::select_active_get(scene);
3093 const int old_type = strip->type;
3094 const int new_type = RNA_enum_get(op->ptr, "type");
3095
3096 /* Free previous effect and init new effect. */
3098
3099 if (!strip->is_effect()) {
3100 return OPERATOR_CANCELLED;
3101 }
3102
3104 BKE_report(op->reports, RPT_ERROR, "New effect takes less or more inputs");
3105 return OPERATOR_CANCELLED;
3106 }
3107
3108 sh = seq::strip_effect_handle_get(strip);
3109 sh.free(strip, true);
3110
3111 strip->type = new_type;
3112
3113 /* If the strip's name is the default (equal to the old effect type),
3114 * rename to the new type to avoid confusion. */
3115 char name_base[MAX_ID_NAME];
3116 int name_num;
3117 BLI_string_split_name_number(strip->name + 2, '.', name_base, &name_num);
3118 if (STREQ(name_base, seq::get_default_stripname_by_type(old_type))) {
3119 seq::edit_strip_name_set(scene, strip, seq::strip_give_name(strip));
3120 seq::ensure_unique_name(strip, scene);
3121 }
3122
3123 sh = seq::strip_effect_handle_get(strip);
3124 sh.init(strip);
3125
3126 seq::relations_invalidate_cache(scene, strip);
3128
3129 return OPERATOR_FINISHED;
3130}
3131
3133{
3134 /* Identifiers. */
3135 ot->name = "Change Effect Type";
3136 ot->idname = "SEQUENCER_OT_change_effect_type";
3137 ot->description = "Replace effect strip with another that takes the same number of inputs";
3138
3139 /* API callbacks. */
3141 ot->poll = sequencer_effect_poll;
3142
3143 /* Flags. */
3144 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3145
3146 ot->prop = RNA_def_enum(ot->srna,
3147 "type",
3150 "Type",
3151 "Strip effect type");
3153}
3154
3156
3157/* -------------------------------------------------------------------- */
3160
3162{
3163 Main *bmain = CTX_data_main(C);
3165 Strip *strip = seq::select_active_get(scene);
3166 const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
3167 const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
3168 int minext_frameme, numdigits;
3169
3170 if (strip->type == STRIP_TYPE_IMAGE) {
3171 char directory[FILE_MAX];
3172 int len;
3173 StripElem *se;
3174
3175 /* Need to find min/max frame for placeholders. */
3176 if (use_placeholders) {
3177 len = sequencer_image_strip_get_minmax_frame(op, strip->sfra, &minext_frameme, &numdigits);
3178 }
3179 else {
3181 }
3182 if (len == 0) {
3183 return OPERATOR_CANCELLED;
3184 }
3185
3186 RNA_string_get(op->ptr, "directory", directory);
3187 if (is_relative_path) {
3188 /* TODO(@ideasman42): shouldn't this already be relative from the filesel?
3189 * (as the 'filepath' is) for now just make relative here,
3190 * but look into changing after 2.60. */
3191 BLI_path_rel(directory, BKE_main_blendfile_path(bmain));
3192 }
3193 STRNCPY(strip->data->dirpath, directory);
3194
3195 if (strip->data->stripdata) {
3196 MEM_freeN(strip->data->stripdata);
3197 }
3198 strip->data->stripdata = se = MEM_calloc_arrayN<StripElem>(len, "stripelem");
3199
3200 if (use_placeholders) {
3201 sequencer_image_strip_reserve_frames(op, se, len, minext_frameme, numdigits);
3202 }
3203 else {
3204 RNA_BEGIN (op->ptr, itemptr, "files") {
3205 std::string filename = RNA_string_get(&itemptr, "name");
3206 STRNCPY(se->filename, filename.c_str());
3207 se++;
3208 }
3209 RNA_END;
3210 }
3211
3212 if (len == 1) {
3214 }
3215 else {
3217 }
3218
3219 /* Reset these else we won't see all the images. */
3220 strip->anim_startofs = strip->anim_endofs = 0;
3221
3222 /* Correct start/end frames so we don't move.
3223 * Important not to set strip->len = len; allow the function to handle it. */
3224 seq::add_reload_new_file(bmain, scene, strip, true);
3225 }
3226 else if (strip->type == STRIP_TYPE_SOUND_RAM) {
3227 bSound *sound = strip->sound;
3228 if (sound == nullptr) {
3229 return OPERATOR_CANCELLED;
3230 }
3231 char filepath[FILE_MAX];
3232 RNA_string_get(op->ptr, "filepath", filepath);
3233 STRNCPY(sound->filepath, filepath);
3234 BKE_sound_load(bmain, sound);
3235 }
3236 else {
3237 /* Lame, set rna filepath. */
3238 PropertyRNA *prop;
3239 char filepath[FILE_MAX];
3240
3241 PointerRNA strip_ptr = RNA_pointer_create_discrete(&scene->id, &RNA_Strip, strip);
3242
3243 RNA_string_get(op->ptr, "filepath", filepath);
3244 prop = RNA_struct_find_property(&strip_ptr, "filepath");
3245 RNA_property_string_set(&strip_ptr, prop, filepath);
3246 RNA_property_update(C, &strip_ptr, prop);
3248 }
3249
3252
3253 return OPERATOR_FINISHED;
3254}
3255
3257 wmOperator *op,
3258 const wmEvent * /*event*/)
3259{
3261 Strip *strip = seq::select_active_get(scene);
3262 char filepath[FILE_MAX];
3263
3265 filepath, sizeof(filepath), strip->data->dirpath, strip->data->stripdata->filename);
3266
3267 RNA_string_set(op->ptr, "directory", strip->data->dirpath);
3268 RNA_string_set(op->ptr, "filepath", filepath);
3269
3270 /* Set default display depending on strip type. */
3271 if (strip->type == STRIP_TYPE_IMAGE) {
3272 RNA_boolean_set(op->ptr, "filter_movie", false);
3273 }
3274 else {
3275 RNA_boolean_set(op->ptr, "filter_image", false);
3276 }
3277
3279
3281}
3282
3284{
3285 /* Identifiers. */
3286 ot->name = "Change Data/Files";
3287 ot->idname = "SEQUENCER_OT_change_path";
3288
3289 /* API callbacks. */
3293
3294 /* Flags. */
3295 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3296
3305 RNA_def_boolean(ot->srna,
3306 "use_placeholders",
3307 false,
3308 "Use Placeholders",
3309 "Use placeholders for missing frames of the strip");
3310}
3311
3313
3314/* -------------------------------------------------------------------- */
3317
3319{
3321 if (ed == nullptr) {
3322 return false;
3323 }
3324 Strip *strip = ed->act_strip;
3325 return ((strip != nullptr) && (strip->type == STRIP_TYPE_SCENE));
3326}
3328{
3329 Main *bmain = CTX_data_main(C);
3331 Scene *scene_seq = static_cast<Scene *>(
3332 BLI_findlink(&bmain->scenes, RNA_enum_get(op->ptr, "scene")));
3333
3334 if (scene_seq == nullptr) {
3335 BKE_report(op->reports, RPT_ERROR, "Scene not found");
3336 return OPERATOR_CANCELLED;
3337 }
3338
3339 /* Assign new scene. */
3340 Strip *strip = seq::select_active_get(scene);
3341 if (strip) {
3342 strip->scene = scene_seq;
3343 /* Do a refresh of the sequencer data. */
3347 }
3348
3351
3352 return OPERATOR_FINISHED;
3353}
3354
3356 wmOperator *op,
3357 const wmEvent *event)
3358{
3359 if (!RNA_struct_property_is_set(op->ptr, "scene")) {
3360 return WM_enum_search_invoke(C, op, event);
3361 }
3362
3363 return sequencer_change_scene_exec(C, op);
3364}
3365
3367{
3368 PropertyRNA *prop;
3369
3370 /* Identifiers. */
3371 ot->name = "Change Scene";
3372 ot->idname = "SEQUENCER_OT_change_scene";
3373 ot->description = "Change Scene assigned to Strip";
3374
3375 /* API callbacks. */
3379
3380 /* Flags. */
3381 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3382
3383 /* Properties. */
3384 prop = RNA_def_enum(ot->srna, "scene", rna_enum_dummy_NULL_items, 0, "Scene", "");
3387 ot->prop = prop;
3388}
3389
3391
3392/* -------------------------------------------------------------------- */
3395
3397static int strip_cmp_time_startdisp_channel(void *thunk, const void *a, const void *b)
3398{
3399 const Scene *scene = static_cast<Scene *>(thunk);
3400 const Strip *strip_a = static_cast<const Strip *>(a);
3401 const Strip *strip_b = static_cast<const Strip *>(b);
3402
3403 int strip_a_start = seq::time_left_handle_frame_get(scene, strip_a);
3404 int strip_b_start = seq::time_left_handle_frame_get(scene, strip_b);
3405
3406 /* If strips have the same start frame favor the one with a higher channel. */
3407 if (strip_a_start == strip_b_start) {
3408 return strip_a->channel > strip_b->channel;
3409 }
3410
3411 return (strip_a_start > strip_b_start);
3412}
3413
3415 wmOperator *op,
3416 const wmEvent * /*event*/)
3417{
3419
3421
3423}
3424
3429
3430static bool strip_get_text_strip_cb(Strip *strip, void *user_data)
3431{
3432 Seq_get_text_cb_data *cd = (Seq_get_text_cb_data *)user_data;
3435 /* Only text strips that are not muted and don't end with negative frame. */
3436 if ((strip->type == STRIP_TYPE_TEXT) && !seq::render_is_muted(channels, strip) &&
3437 (seq::time_right_handle_frame_get(cd->scene, strip) > cd->scene->r.sfra))
3438 {
3439 BLI_addtail(cd->text_seq, MEM_dupallocN(strip));
3440 }
3441 return true;
3442}
3443
3445{
3447 Strip *strip, *strip_next;
3448 Editing *ed = seq::editing_get(scene);
3449 ListBase text_seq = {nullptr};
3450 int iter = 1; /* Sequence numbers in `.srt` files are 1-indexed. */
3451 FILE *file;
3452 char filepath[FILE_MAX];
3453
3454 if (!RNA_struct_property_is_set_ex(op->ptr, "filepath", false)) {
3455 BKE_report(op->reports, RPT_ERROR, "No filepath given");
3456 return OPERATOR_CANCELLED;
3457 }
3458
3459 RNA_string_get(op->ptr, "filepath", filepath);
3460 BLI_path_extension_ensure(filepath, sizeof(filepath), ".srt");
3461
3462 /* Avoid File write exceptions. */
3463 if (!BLI_exists(filepath)) {
3465 if (!BLI_file_touch(filepath)) {
3466 BKE_report(op->reports, RPT_ERROR, "Cannot create subtitle file");
3467 return OPERATOR_CANCELLED;
3468 }
3469 }
3470 else if (!BLI_file_is_writable(filepath)) {
3471 BKE_report(op->reports, RPT_ERROR, "Cannot overwrite export file");
3472 return OPERATOR_CANCELLED;
3473 }
3474
3475 if (ed != nullptr) {
3476 Seq_get_text_cb_data cb_data = {&text_seq, scene};
3477 seq::foreach_strip(&ed->seqbase, strip_get_text_strip_cb, &cb_data);
3478 }
3479
3480 if (BLI_listbase_is_empty(&text_seq)) {
3481 BKE_report(op->reports, RPT_ERROR, "No subtitles (text strips) to export");
3482 return OPERATOR_CANCELLED;
3483 }
3484
3486
3487 /* Open and write file. */
3488 file = BLI_fopen(filepath, "w");
3489
3490 for (strip = static_cast<Strip *>(text_seq.first); strip; strip = strip_next) {
3491 TextVars *data = static_cast<TextVars *>(strip->effectdata);
3492 char timecode_str_start[32];
3493 char timecode_str_end[32];
3494
3495 /* Write time-code relative to start frame of scene. Don't allow negative time-codes. */
3497 timecode_str_start,
3498 sizeof(timecode_str_start),
3499 -2,
3500 FRA2TIME(max_ii(seq::time_left_handle_frame_get(scene, strip) - scene->r.sfra, 0)),
3501 scene->frames_per_second(),
3504 timecode_str_end,
3505 sizeof(timecode_str_end),
3506 -2,
3507 FRA2TIME(seq::time_right_handle_frame_get(scene, strip) - scene->r.sfra),
3508 scene->frames_per_second(),
3510
3511 fprintf(file,
3512 "%d\n%s --> %s\n%s\n\n",
3513 iter++,
3514 timecode_str_start,
3515 timecode_str_end,
3516 data->text_ptr);
3517
3518 strip_next = static_cast<Strip *>(strip->next);
3519 MEM_freeN(strip);
3520 }
3521
3522 fclose(file);
3523
3524 return OPERATOR_FINISHED;
3525}
3526
3528{
3530 if (!scene) {
3531 return false;
3532 }
3533 Editing *ed = seq::editing_get(scene);
3534 if (!ed) {
3535 return false;
3536 }
3537 Strip *strip = ed->act_strip;
3538 if (!strip) {
3539 return false;
3540 }
3541 return strip->type == STRIP_TYPE_TEXT;
3542}
3543
3545{
3546 /* Identifiers. */
3547 ot->name = "Export Subtitles";
3548 ot->idname = "SEQUENCER_OT_export_subtitles";
3549 ot->description = "Export .srt file containing text strips";
3550
3551 /* API callbacks. */
3555
3556 /* Flags. */
3557 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3558
3562 FILE_SAVE,
3566}
3567
3569
3570/* -------------------------------------------------------------------- */
3573
3575{
3577 Editing *ed = seq::editing_get(scene);
3578
3579 int sfra = MAXFRAME;
3580 int efra = -MAXFRAME;
3581 bool selected = false;
3582 const bool preview = RNA_boolean_get(op->ptr, "preview");
3583
3584 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
3585 if (strip->flag & SELECT) {
3586 selected = true;
3587 sfra = min_ii(sfra, seq::time_left_handle_frame_get(scene, strip));
3588 /* Offset of -1 is needed because in the sequencer every frame has width.
3589 * Range from 1 to 1 is drawn as range 1 to 2, because 1 frame long strip starts at frame 1
3590 * and ends at frame 2. See #106480. */
3591 efra = max_ii(efra, seq::time_right_handle_frame_get(scene, strip) - 1);
3592 }
3593 }
3594
3595 if (!selected) {
3596 BKE_report(op->reports, RPT_WARNING, "Select one or more strips");
3597 return OPERATOR_CANCELLED;
3598 }
3599 if (efra < 0) {
3600 BKE_report(op->reports, RPT_ERROR, "Cannot set a negative range");
3601 return OPERATOR_CANCELLED;
3602 }
3603
3604 if (preview) {
3605 scene->r.flag |= SCER_PRV_RANGE;
3606 scene->r.psfra = max_ii(0, sfra);
3607 scene->r.pefra = efra;
3608 }
3609 else {
3610 scene->r.flag &= ~SCER_PRV_RANGE;
3611 scene->r.sfra = max_ii(0, sfra);
3612 scene->r.efra = efra;
3613 }
3614
3616
3617 return OPERATOR_FINISHED;
3618}
3619
3621{
3622 PropertyRNA *prop;
3623
3624 /* Identifiers. */
3625 ot->name = "Set Range to Strips";
3626 ot->idname = "SEQUENCER_OT_set_range_to_strips";
3627 ot->description = "Set the frame range to the selected strips start and end";
3628
3629 /* API callbacks. */
3631 ot->poll = sequencer_edit_poll;
3632
3633 /* Flags. */
3634 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3635
3636 prop = RNA_def_boolean(ot->srna, "preview", false, "Preview", "Set the preview range instead");
3638}
3639
3641
3642/* -------------------------------------------------------------------- */
3645
3646enum {
3651};
3652
3654 {STRIP_TRANSFORM_POSITION, "POSITION", 0, "Position", "Reset strip transform location"},
3655 {STRIP_TRANSFORM_SCALE, "SCALE", 0, "Scale", "Reset strip transform scale"},
3656 {STRIP_TRANSFORM_ROTATION, "ROTATION", 0, "Rotation", "Reset strip transform rotation"},
3657 {STRIP_TRANSFORM_ALL, "ALL", 0, "All", "Reset strip transform location, scale and rotation"},
3658 {0, nullptr, 0, nullptr, nullptr},
3659};
3660
3662{
3664 const Editing *ed = seq::editing_get(scene);
3665 const int property = RNA_enum_get(op->ptr, "property");
3666
3667 const bool use_autokeyframe = blender::animrig::is_autokey_on(scene);
3668 const bool only_when_keyed = blender::animrig::is_keying_flag(scene,
3670
3671 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
3672 if (strip->flag & SELECT && strip->type != STRIP_TYPE_SOUND_RAM) {
3673 StripTransform *transform = strip->data->transform;
3674 PropertyRNA *prop;
3675 PointerRNA ptr = RNA_pointer_create_discrete(&scene->id, &RNA_StripTransform, transform);
3676 switch (property) {
3678 transform->xofs = 0;
3679 transform->yofs = 0;
3680 if (use_autokeyframe) {
3681 prop = RNA_struct_find_property(&ptr, "offset_x");
3683 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3684 prop = RNA_struct_find_property(&ptr, "offset_y");
3686 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3687 }
3688 break;
3690 transform->scale_x = 1.0f;
3691 transform->scale_y = 1.0f;
3692 if (use_autokeyframe) {
3693 prop = RNA_struct_find_property(&ptr, "scale_x");
3695 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3696 prop = RNA_struct_find_property(&ptr, "scale_y");
3698 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3699 }
3700 break;
3702 transform->rotation = 0.0f;
3703 if (use_autokeyframe) {
3704 prop = RNA_struct_find_property(&ptr, "rotation");
3706 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3707 }
3708 break;
3710 transform->xofs = 0;
3711 transform->yofs = 0;
3712 transform->scale_x = 1.0f;
3713 transform->scale_y = 1.0f;
3714 transform->rotation = 0.0f;
3715 if (use_autokeyframe) {
3716 prop = RNA_struct_find_property(&ptr, "offset_x");
3718 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3719 prop = RNA_struct_find_property(&ptr, "offset_y");
3721 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3722 prop = RNA_struct_find_property(&ptr, "scale_x");
3724 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3725 prop = RNA_struct_find_property(&ptr, "scale_y");
3727 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3728 prop = RNA_struct_find_property(&ptr, "rotation");
3730 C, scene, &ptr, prop, -1, scene->r.cfra, only_when_keyed);
3731 }
3732 break;
3733 }
3734 seq::relations_invalidate_cache(scene, strip);
3735 }
3736 }
3737
3739 return OPERATOR_FINISHED;
3740}
3741
3743{
3744 /* Identifiers. */
3745 ot->name = "Clear Strip Transform";
3746 ot->idname = "SEQUENCER_OT_strip_transform_clear";
3747 ot->description = "Reset image transformation to default value";
3748
3749 /* API callbacks. */
3751 ot->poll = sequencer_edit_poll;
3752
3753 /* Flags. */
3754 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3755
3756 ot->prop = RNA_def_enum(ot->srna,
3757 "property",
3760 "Property",
3761 "Strip transform property to be reset");
3762}
3763
3765
3766/* -------------------------------------------------------------------- */
3769
3771{
3773 const Editing *ed = seq::editing_get(scene);
3774 const eSeqImageFitMethod fit_method = eSeqImageFitMethod(RNA_enum_get(op->ptr, "fit_method"));
3775
3776 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
3777 if (strip->flag & SELECT && strip->type != STRIP_TYPE_SOUND_RAM) {
3778 const int timeline_frame = scene->r.cfra;
3779 StripElem *strip_elem = seq::render_give_stripelem(scene, strip, timeline_frame);
3780
3781 if (strip_elem == nullptr) {
3782 continue;
3783 }
3784
3786 strip_elem->orig_width,
3787 strip_elem->orig_height,
3788 scene->r.xsch,
3789 scene->r.ysch,
3790 fit_method);
3791 seq::relations_invalidate_cache(scene, strip);
3792 }
3793 }
3794
3796 return OPERATOR_FINISHED;
3797}
3798
3800{
3801 /* Identifiers. */
3802 ot->name = "Strip Transform Set Fit";
3803 ot->idname = "SEQUENCER_OT_strip_transform_fit";
3804
3805 /* API callbacks. */
3807 ot->poll = sequencer_edit_poll;
3808
3809 /* Flags. */
3810 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3811
3812 ot->prop = RNA_def_enum(ot->srna,
3813 "fit_method",
3816 "Fit Method",
3817 "Mode for fitting the image to the canvas");
3818}
3819
3821{
3823 const Editing *ed = seq::editing_get(scene);
3824 const short color_tag = RNA_enum_get(op->ptr, "color");
3825
3826 LISTBASE_FOREACH (Strip *, strip, ed->current_strips()) {
3827 if (strip->flag & SELECT) {
3828 strip->color_tag = color_tag;
3829 }
3830 }
3831
3833 return OPERATOR_FINISHED;
3834}
3835
3837{
3839 if (scene == nullptr) {
3840 return false;
3841 }
3842
3843 Editing *ed = seq::editing_get(scene);
3844 if (ed == nullptr) {
3845 return false;
3846 }
3847
3848 Strip *act_strip = ed->act_strip;
3849 return act_strip != nullptr;
3850}
3851
3853{
3854 /* Identifiers. */
3855 ot->name = "Set Color Tag";
3856 ot->idname = "SEQUENCER_OT_strip_color_tag_set";
3857 ot->description = "Set a color tag for the selected strips";
3858
3859 /* API callbacks. */
3862
3863 /* Flags. */
3864 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3865
3866 RNA_def_enum(ot->srna, "color", rna_enum_strip_color_items, STRIP_COLOR_NONE, "Color Tag", "");
3867}
3868
3870
3871/* -------------------------------------------------------------------- */
3874
3876{
3878 SpaceSeq *sseq = CTX_wm_space_seq(C);
3879
3880 float cursor_pixel[2];
3881 RNA_float_get_array(op->ptr, "location", cursor_pixel);
3882
3883 blender::float2 cursor_region = seq::image_preview_unit_from_px(scene, cursor_pixel);
3884 copy_v2_v2(sseq->cursor, cursor_region);
3885
3887
3888 /* Use pass-through to allow click-drag to transform the cursor. */
3890}
3891
3893 wmOperator *op,
3894 const wmEvent *event)
3895{
3896 ARegion *region = CTX_wm_region(C);
3897 float cursor_pixel[2];
3899 &region->v2d, event->mval[0], event->mval[1], &cursor_pixel[0], &cursor_pixel[1]);
3900
3901 RNA_float_set_array(op->ptr, "location", cursor_pixel);
3902
3903 return sequencer_set_2d_cursor_exec(C, op);
3904}
3905
3907{
3908 /* identifiers */
3909 ot->name = "Set 2D Cursor";
3910 ot->description = "Set 2D cursor location";
3911 ot->idname = "SEQUENCER_OT_cursor_set";
3912
3913 /* API callbacks. */
3917
3918 /* flags */
3919 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3920
3921 /* properties */
3923 "location",
3924 2,
3925 nullptr,
3926 -FLT_MAX,
3927 FLT_MAX,
3928 "Location",
3929 "Cursor location in normalized preview coordinates",
3930 -10.0f,
3931 10.0f);
3932}
3933
3935
3936/* -------------------------------------------------------------------- */
3939
3941{
3943 Editing *ed = seq::editing_get(scene);
3944 Strip *strip = ed->act_strip;
3945
3946 const int old_start = seq::time_left_handle_frame_get(scene, strip);
3947 const int old_end = seq::time_right_handle_frame_get(scene, strip);
3948
3949 Scene *target_scene = strip->scene;
3950
3951 strip->len = target_scene->r.efra - target_scene->r.sfra + 1;
3952 seq::time_handles_frame_set(scene, strip, old_start, old_end);
3953
3957 return OPERATOR_FINISHED;
3958}
3959
3961{
3963 return (ed != nullptr && ed->act_strip != nullptr && ed->act_strip->type == STRIP_TYPE_SCENE);
3964}
3965
3967{
3968 /* identifiers */
3969 ot->name = "Update Scene Frame Range";
3970 ot->description = "Update frame range of scene strip";
3971 ot->idname = "SEQUENCER_OT_scene_frame_range_update";
3972
3973 /* API callbacks. */
3976
3977 /* flags */
3978 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3979}
3980
3982
3983} // namespace blender::ed::vse
Functions for backward compatibility with the legacy Action API.
WorkSpace * CTX_wm_workspace(const bContext *C)
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Object * CTX_data_active_object(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)
wmWindowManager * CTX_wm_manager(const bContext *C)
Scene * CTX_data_sequencer_scene(const bContext *C)
const char * BKE_idtype_idcode_to_name(short idcode)
Definition idtype.cc:164
const char * BKE_idtype_idcode_to_name_plural(short idcode)
Definition idtype.cc:171
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
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:360
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:452
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
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
int bool bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(1
#define SNPRINTF_UTF8(dst, format,...)
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
size_t BLI_string_split_name_number(const char *name, char delim, char *r_name_left, int *r_number) 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 RPT_(msgid)
#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:1125
@ ID_RECALC_AUDIO
Definition DNA_ID.h:1132
@ ID_RECALC_SEQUENCER_STRIPS
Definition DNA_ID.h:1122
@ ID_RECALC_ANIMATION_NO_FLUSH
Definition DNA_ID.h:1176
#define MAX_ID_NAME
Definition DNA_ID.h:373
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:705
@ ID_MC
@ ID_SCE
@ ID_MSK
eObjectMode
eSeqImageFitMethod
@ SEQ_SCALE_TO_FIT
@ SCER_SHOW_SUBFRAME
@ SCER_PRV_RANGE
#define FRA2TIME(a)
#define MAXFRAME
@ RGN_TYPE_CHANNELS
@ RGN_TYPE_WINDOW
@ RGN_TYPE_PREVIEW
@ STRIP_IGNORE_CHANNEL_LOCK
@ STRIP_SHOW_OFFSETS
@ STRIP_OVERLAP
@ STRIP_CLAMPED_LH
@ STRIP_CLAMPED_RH
@ STRIP_TYPE_GAUSSIAN_BLUR
@ STRIP_TYPE_GAMCROSS
@ STRIP_TYPE_SCENE
@ STRIP_TYPE_MOVIECLIP
@ STRIP_TYPE_COLORMIX
@ STRIP_TYPE_WIPE
@ STRIP_TYPE_TEXT
@ STRIP_TYPE_SOUND_RAM
@ STRIP_TYPE_ADD
@ STRIP_TYPE_IMAGE
@ STRIP_TYPE_MOVIE
@ STRIP_TYPE_GLOW
@ STRIP_TYPE_SUB
@ STRIP_TYPE_MUL
@ STRIP_TYPE_SPEED
@ STRIP_TYPE_COLOR
@ STRIP_TYPE_ADJUSTMENT
@ STRIP_TYPE_META
@ STRIP_TYPE_MULTICAM
@ STRIP_TYPE_MASK
@ STRIP_TYPE_ALPHAUNDER
@ STRIP_TYPE_CROSS
@ STRIP_TYPE_ALPHAOVER
@ STRIP_COLOR_NONE
#define STRIP_ALLSEL
@ SEQ_SINGLE_FRAME_CONTENT
@ SEQ_RIGHTSEL
@ SEQ_LEFTSEL
#define STRIP_HAS_PATH(_strip)
@ FILE_SORT_DEFAULT
@ FILE_SPECIAL
@ FILE_BLENDER
@ FILE_TYPE_FOLDER
@ SPACE_VIEW3D
@ SEQ_VIEW_SEQUENCE_PREVIEW
@ SEQ_VIEW_SEQUENCE
@ SEQ_VIEW_PREVIEW
@ FILE_DEFAULTDISPLAY
@ SEQ_DRAW_IMG_IMBUF
#define FRAMENUMBER_MIN_CLAMP(cfra)
@ AUTOKEY_FLAG_INSERTAVAILABLE
@ USER_TIMECODE_SUBRIP
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ OPERATOR_RUNNING_MODAL
@ OPERATOR_PASS_THROUGH
@ WORKSPACE_SYNC_SCENE_TIME
void ED_fileselect_ensure_default_filepath(bContext *C, wmOperator *op, const char *extension)
Definition filesel.cc:1470
void initNumInput(NumInput *n)
Definition numinput.cc:70
#define NUM_STR_REP_LEN
bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event)
Definition numinput.cc:312
bool applyNumInput(NumInput *n, float *vec)
Definition numinput.cc:190
void outputNumInput(NumInput *n, char *str, const UnitSettings &unit_settings)
Definition numinput.cc:88
bool hasNumInput(const NumInput *n)
Definition numinput.cc:171
bool ED_scene_delete(bContext *C, Main *bmain, Scene *scene) ATTR_NONNULL()
Definition scene_edit.cc:93
void ED_area_status_text(ScrArea *area, const char *str)
Definition area.cc:851
bool ED_operator_sequencer_active(bContext *C)
bScreen * ED_screen_animation_playing(const wmWindowManager *wm)
void ED_workspace_status_text(bContext *C, const char *str)
Definition area.cc:1024
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
#define RNA_BEGIN(sptr, itemptr, propname)
#define RNA_END
const EnumPropertyItem * RNA_scene_without_sequencer_scene_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *prop, bool *r_free)
@ PROP_ENUM_NO_TRANSLATE
Definition RNA_types.hh:432
@ PROP_SKIP_SAVE
Definition RNA_types.hh:344
@ PROP_HIDDEN
Definition RNA_types.hh:338
#define C
Definition RandGen.cpp:29
@ UI_ITEM_R_EXPAND
#define UI_ITEM_NONE
#define UI_MAX_DRAW_STR
View2D * UI_view2d_fromcontext(const bContext *C)
Definition view2d.cc:1855
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:1668
float UI_view2d_scale_get_x(const View2D *v2d)
Definition view2d.cc:1921
@ WM_FILESEL_FILES
Definition WM_api.hh:1125
@ WM_FILESEL_DIRECTORY
Definition WM_api.hh:1122
@ WM_FILESEL_RELPATH
Definition WM_api.hh:1121
@ WM_FILESEL_FILEPATH
Definition WM_api.hh:1124
@ FILE_OPENFILE
Definition WM_api.hh:1133
@ FILE_SAVE
Definition WM_api.hh:1134
#define ND_SEQUENCER
Definition WM_types.hh:437
#define ND_SPACE_SEQUENCER
Definition WM_types.hh:535
#define NC_WINDOW
Definition WM_types.hh:375
#define ND_RENDER_OPTIONS
Definition WM_types.hh:435
@ KM_PRESS
Definition WM_types.hh:311
#define NC_SCENE
Definition WM_types.hh:378
@ 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 ND_FRAME_RANGE
Definition WM_types.hh:451
#define ND_FRAME
Definition WM_types.hh:434
#define NA_REMOVED
Definition WM_types.hh:587
#define ND_SCENEBROWSE
Definition WM_types.hh:432
#define ND_ANIMCHAN
Definition WM_types.hh:496
#define NC_SPACE
Definition WM_types.hh:392
BMesh const char void * data
long long int int64_t
int64_t size() const
Definition BLI_set.hh:587
bool add(const Key &key)
Definition BLI_set.hh:248
constexpr bool is_empty() const
constexpr const char * data() const
bool add(const Key &key)
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
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)
bool mode_set(bContext *C, eObjectMode mode)
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 *op)
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 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)
wmOperatorStatus sequencer_clipboard_copy_exec(bContext *C, wmOperator *op)
static wmOperatorStatus sequencer_gap_insert_exec(bContext *C, wmOperator *op)
void sequencer_image_strip_reserve_frames(wmOperator *op, StripElem *se, int len, int minframe, int numdigits)
static wmOperatorStatus sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *)
void SEQUENCER_OT_gap_remove(wmOperatorType *ot)
static void slip_handle_num_input(bContext *C, wmOperator *op, ScrArea *area, SlipData *data, Scene *scene)
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)
blender::VectorSet< Strip * > all_strips_from_context(bContext *C)
bool is_scene_time_sync_needed(const 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 SlipData * slip_data_init(bContext *C, const wmOperator *op, const wmEvent *event)
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)
void sync_active_scene_and_time_with_scene_strip(bContext &C)
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)
const Strip * get_scene_strip_for_time_sync(const Scene *sequence_scene)
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)
static Scene * get_sequencer_scene_for_time_sync(const bContext &C)
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 void slip_strips_delta(bContext *C, wmOperator *op, Scene *scene, SlipData *data, const float delta)
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)
wmOperatorStatus sequencer_clipboard_paste_invoke(bContext *C, wmOperator *op, const wmEvent *event)
const EnumPropertyItem prop_side_types[]
static bool sequencer_scene_frame_range_update_poll(bContext *C)
void SEQUENCER_OT_delete(wmOperatorType *ot)
static wmOperatorStatus sequencer_strip_transform_clear_exec(bContext *C, wmOperator *op)
void SEQUENCER_OT_meta_separate(wmOperatorType *ot)
static void sequencer_report_duplicates(wmOperator *op, ListBase *duplicated_strips)
static bool sequencer_effect_poll(bContext *C)
bool sequencer_view_strips_poll(bContext *C)
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)
int sequencer_image_strip_get_minmax_frame(wmOperator *op, int sfra, int *r_minframe, int *r_numdigits)
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:2110
void relations_strip_free_anim(Strip *strip)
void prefetch_stop(Scene *scene)
Definition prefetch.cc:310
int time_right_handle_frame_get(const Scene *scene, const Strip *strip)
void foreach_strip(ListBase *seqbase, ForEachFunc callback, void *user_data)
Definition iterator.cc:59
bool disconnect(Strip *strip)
void relations_invalidate_cache(Scene *scene, Strip *strip)
EffectHandle strip_effect_handle_get(Strip *strip)
Definition effects.cc:290
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:60
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:152
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)
float give_frame_index(const Scene *scene, const Strip *strip, float timeline_frame)
Definition strip_time.cc:52
bool transform_test_overlap(const Scene *scene, Strip *strip1, Strip *strip2)
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:286
void meta_stack_set(const Scene *scene, Strip *dst)
Definition sequencer.cc:463
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)
blender::VectorSet< Strip * > connected_strips_get(const Strip *strip)
void add_reload_new_file(Main *bmain, Scene *scene, Strip *strip, const bool lock_range)
Definition strip_add.cc:538
Strip * select_active_get(const Scene *scene)
static void query_strips_recursive_at_frame(const Scene *scene, const ListBase *seqbase, const int timeline_frame, VectorSet< Strip * > &strips)
Definition iterator.cc:118
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 time_handles_frame_set(const Scene *scene, Strip *strip, int left_handle_timeline_frame, int right_handle_timeline_frame)
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)
Strip * strip_duplicate_recursive(Main *bmain, const Scene *scene_src, Scene *scene_dst, ListBase *new_seq_list, Strip *strip, const StripDuplicate dupe_flag)
Definition sequencer.cc:766
void query_strip_connected_and_effect_chain(const Scene *scene, Strip *reference_strip, ListBase *seqbase, VectorSet< Strip * > &r_strips)
Definition iterator.cc:283
ListBase * active_seqbase_get(const Editing *ed)
Definition sequencer.cc:433
void time_right_handle_frame_set(const Scene *scene, Strip *strip, int timeline_frame)
Strip * meta_stack_pop(Editing *ed)
Definition sequencer.cc:484
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:136
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)
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:238
void seqbase_duplicate_recursive(Main *bmain, const Scene *scene_src, Scene *scene_dst, ListBase *nseqbase, const ListBase *seqbase, const StripDuplicate dupe_flag, const int flag)
Definition sequencer.cc:819
float2 image_preview_unit_from_px(const Scene *scene, const float2 co_src)
int effect_get_num_inputs(int strip_type)
Definition effects.cc:327
VecBase< float, 2 > float2
static blender::bke::bNodeSocketTemplate inputs[]
const int status
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
void RNA_pointer_set(PointerRNA *ptr, const char *name, PointerRNA ptr_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)
int RNA_int_get(PointerRNA *ptr, const char *name)
float RNA_float_get(PointerRNA *ptr, const char *name)
std::string RNA_string_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)
PointerRNA RNA_id_pointer_create(ID *id)
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[]
const EnumPropertyItem rna_enum_strip_scale_method_items[]
#define FLT_MAX
Definition stdcycles.h:14
bAction * action
char * rna_path
void * last
void * first
ListBase scenes
Definition BKE_main.hh:278
struct Editing * ed
struct RenderData r
struct AnimData * adt
struct UnitSettings unit
struct Object * camera
ListBase markers
float cursor[2]
StripTransform * transform
StripElem * stripdata
char dirpath[768]
char filename[256]
struct Object * scene_camera
void * scene_sound
struct Strip * input1
StripData * data
struct Scene * scene
void * effectdata
struct bSound * sound
ListBase seqbase
StripRuntime runtime
struct Strip * next
float sound_offset
char name[64]
struct Strip * input2
ListBase channels
struct Scene * sequencer_scene
struct wmTimer * animtimer
ListBase areabase
char filepath[1024]
VectorSet< Strip * > strips
void(* free)(Strip *strip, bool do_id_user)
void(* init)(Strip *strip)
void use_property_decorate_set(bool is_sep)
void separator(float factor=1.0f, LayoutSeparatorType type=LayoutSeparatorType::Auto)
uiLayout & row(bool align)
void use_property_split_set(bool value)
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:757
short val
Definition WM_types.hh:759
int mval[2]
Definition WM_types.hh:763
const void * modal_items
struct ReportList * reports
struct uiLayout * layout
struct wmOperatorType * type
struct PointerRNA * ptr
void * customdata
Definition WM_types.hh:965
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:4238
wmOperatorType * ot
Definition wm_files.cc:4237
wmKeyMap * WM_modalkeymap_ensure(wmKeyConfig *keyconf, const char *idname, const EnumPropertyItem *items)
Definition wm_keymap.cc:932
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
wmKeyMap * WM_modalkeymap_find(wmKeyConfig *keyconf, const char *idname)
Definition wm_keymap.cc:959
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_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *)
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, std::optional< std::string > message)
void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
Scene * WM_window_get_active_scene(const wmWindow *win)
bScreen * WM_window_get_active_screen(const wmWindow *win)