diff options
Diffstat (limited to 'source')
27 files changed, 1062 insertions, 259 deletions
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 66c17ff8115..82cc518f029 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -202,6 +202,21 @@ int ED_transform_calc_gizmo_stats(const struct bContext *C, const struct TransformCalcParams *params, struct TransformBounds *tbounds); +/** + * Iterates over all the strips and finds the closest snapping candidate of either \a frame_1 or \a + * frame_2. The closest snapping candidate will be the closest start or end frame of an existing + * strip. + * \returns True if there was anything to snap to. + */ +bool ED_transform_snap_sequencer_to_closest_strip_calc(struct Scene *scene, + struct ARegion *region, + int frame_1, + int frame_2, + int *r_snap_distance, + float *r_snap_frame); + +void ED_draw_sequencer_snap_point(struct bContext *C, float snap_point); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 1b817d06564..9f4d6815287 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -2925,7 +2925,7 @@ void ED_keymap_ui(struct wmKeyConfig *keyconf); void ED_dropboxes_ui(void); void ED_uilisttypes_ui(void); -void UI_drop_color_copy(struct wmDrag *drag, struct wmDropBox *drop); +void UI_drop_color_copy(struct bContext *C, struct wmDrag *drag, struct wmDropBox *drop); bool UI_drop_color_poll(struct bContext *C, struct wmDrag *drag, const struct wmEvent *event); bool UI_context_copy_to_selected_list(struct bContext *C, diff --git a/source/blender/editors/interface/interface_dropboxes.cc b/source/blender/editors/interface/interface_dropboxes.cc index 2e8708827e7..9d3c1372b15 100644 --- a/source/blender/editors/interface/interface_dropboxes.cc +++ b/source/blender/editors/interface/interface_dropboxes.cc @@ -67,7 +67,7 @@ static bool ui_drop_name_poll(struct bContext *C, wmDrag *drag, const wmEvent *U return UI_but_active_drop_name(C) && (drag->type == WM_DRAG_ID); } -static void ui_drop_name_copy(wmDrag *drag, wmDropBox *drop) +static void ui_drop_name_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { const ID *id = WM_drag_get_local_ID(drag, 0); RNA_string_set(drop->ptr, "string", id->name + 2); @@ -85,7 +85,7 @@ static bool ui_drop_material_poll(bContext *C, wmDrag *drag, const wmEvent *UNUS return WM_drag_is_ID_type(drag, ID_MA) && !RNA_pointer_is_null(&mat_slot); } -static void ui_drop_material_copy(wmDrag *drag, wmDropBox *drop) +static void ui_drop_material_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { const ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, ID_MA); RNA_int_set(drop->ptr, "session_uuid", (int)id->session_uuid); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 0f4f0ef48ff..5b97a80d513 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1862,7 +1862,7 @@ bool UI_drop_color_poll(struct bContext *C, wmDrag *drag, const wmEvent *UNUSED( return 0; } -void UI_drop_color_copy(wmDrag *drag, wmDropBox *drop) +void UI_drop_color_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { uiDragColorHandle *drag_info = drag->poin; diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 408ddfe7241..d7cf09ca89a 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -5771,7 +5771,7 @@ static bool blend_file_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEven return false; } -static void blend_file_drop_copy(wmDrag *drag, wmDropBox *drop) +static void blend_file_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { /* copy drag path to properties */ RNA_string_set(drop->ptr, "filepath", drag->path); diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 444ed421083..91fef23019c 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -597,7 +597,7 @@ static bool clip_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNU return false; } -static void clip_drop_copy(wmDrag *drag, wmDropBox *drop) +static void clip_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { PointerRNA itemptr; char dir[FILE_MAX], file[FILE_MAX]; diff --git a/source/blender/editors/space_console/space_console.c b/source/blender/editors/space_console/space_console.c index 8e33f7fa97f..c69b73e377d 100644 --- a/source/blender/editors/space_console/space_console.c +++ b/source/blender/editors/space_console/space_console.c @@ -149,7 +149,7 @@ static bool id_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSE return WM_drag_get_local_ID(drag, 0) != NULL; } -static void id_drop_copy(wmDrag *drag, wmDropBox *drop) +static void id_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { ID *id = WM_drag_get_local_ID(drag, 0); @@ -164,7 +164,7 @@ static bool path_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNU return (drag->type == WM_DRAG_PATH); } -static void path_drop_copy(wmDrag *drag, wmDropBox *drop) +static void path_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { char pathname[FILE_MAX + 2]; BLI_snprintf(pathname, sizeof(pathname), "\"%s\"", drag->path); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 7b3b87f4572..0170361f244 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -844,7 +844,7 @@ static bool filepath_drop_poll(bContext *C, wmDrag *drag, const wmEvent *UNUSED( return false; } -static void filepath_drop_copy(wmDrag *drag, wmDropBox *drop) +static void filepath_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { RNA_string_set(drop->ptr, "filepath", drag->path); } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index bc047a00ae1..568bd064e3e 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -255,7 +255,7 @@ static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) return false; } -static void image_drop_copy(wmDrag *drag, wmDropBox *drop) +static void image_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { /* copy drag path to properties */ RNA_string_set(drop->ptr, "filepath", drag->path); diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index 82b850653be..34f357ae5c3 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -636,21 +636,21 @@ static bool node_mask_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent return WM_drag_is_ID_type(drag, ID_MSK); } -static void node_group_drop_copy(wmDrag *drag, wmDropBox *drop) +static void node_group_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); RNA_string_set(drop->ptr, "name", id->name + 2); } -static void node_id_drop_copy(wmDrag *drag, wmDropBox *drop) +static void node_id_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); RNA_int_set(drop->ptr, "session_uuid", (int)id->session_uuid); } -static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) +static void node_id_path_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); diff --git a/source/blender/editors/space_sequencer/CMakeLists.txt b/source/blender/editors/space_sequencer/CMakeLists.txt index 2d1785523d7..b5355efec7a 100644 --- a/source/blender/editors/space_sequencer/CMakeLists.txt +++ b/source/blender/editors/space_sequencer/CMakeLists.txt @@ -25,6 +25,7 @@ set(INC set(SRC sequencer_add.c sequencer_buttons.c + sequencer_drag_drop.c sequencer_draw.c sequencer_channels_draw.c sequencer_channels_edit.c diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 4672961543f..9298eb83b46 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -125,12 +125,20 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag) ot->srna, "channel", 1, 1, MAXSEQ, "Channel", "Channel to place this strip into", 1, MAXSEQ); RNA_def_boolean( - ot->srna, "replace_sel", 1, "Replace Selection", "Replace the current selection"); + ot->srna, "replace_sel", true, "Replace Selection", "Replace the current selection"); /* Only for python scripts which import strips and place them after. */ prop = RNA_def_boolean( - ot->srna, "overlap", 0, "Allow Overlap", "Don't correct overlap on new sequence strips"); - RNA_def_property_flag(prop, PROP_HIDDEN); + ot->srna, "overlap", false, "Allow Overlap", "Don't correct overlap on new sequence strips"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + + prop = RNA_def_boolean( + ot->srna, + "overlap_shuffle_override", + false, + "Override Overlap Shuffle Behaviour", + "Use the overlap_mode tool settings to determine how to shuffle overlapping strips"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); if (flag & SEQPROP_FIT_METHOD) { ot->prop = RNA_def_enum(ot->srna, @@ -205,10 +213,13 @@ static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, i RNA_int_set(op->ptr, "channel", sequencer_generic_invoke_xy_guess_channel(C, type)); } - RNA_int_set(op->ptr, "frame_start", timeline_frame); + if (!RNA_struct_property_is_set(op->ptr, "frame_start")) { + RNA_int_set(op->ptr, "frame_start", timeline_frame); + } if ((flag & SEQPROP_ENDFRAME) && RNA_struct_property_is_set(op->ptr, "frame_end") == 0) { - RNA_int_set(op->ptr, "frame_end", timeline_frame + 25); /* XXX arbitrary but ok for now. */ + RNA_int_set( + op->ptr, "frame_end", RNA_int_get(op->ptr, "frame_start") + DEFAULT_IMG_STRIP_LENGTH); } if (!(flag & SEQPROP_NOPATHS)) { @@ -312,13 +323,53 @@ static void seq_load_apply_generic_options(bContext *C, wmOperator *op, Sequence SEQ_select_active_set(scene, seq); } - if (RNA_boolean_get(op->ptr, "overlap") == false) { - if (SEQ_transform_test_overlap(ed->seqbasep, seq)) { - SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); - } + if (RNA_boolean_get(op->ptr, "overlap") == true || + !SEQ_transform_test_overlap(ed->seqbasep, seq)) { + /* No overlap should be handled or the strip is not overlapping, exit early. */ + return; + } + + if (RNA_boolean_get(op->ptr, "overlap_shuffle_override")) { + /* Use set overlap_mode to fix overlaps. */ + SeqCollection *strip_col = SEQ_collection_create(__func__); + SEQ_collection_append_strip(seq, strip_col); + + ScrArea *area = CTX_wm_area(C); + const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag & SEQ_MARKER_TRANS) != + 0; + SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers); + + SEQ_collection_free(strip_col); + } + else { + /* Shuffle strip channel to fix overlaps. */ + SEQ_transform_seqbase_shuffle(ed->seqbasep, seq, scene); } } +/* In this alternative version we only check for overlap, but do not do anything about them. */ +static bool seq_load_apply_generic_options_only_test_overlap(bContext *C, + wmOperator *op, + Sequence *seq, + SeqCollection *strip_col) +{ + Scene *scene = CTX_data_scene(C); + Editing *ed = SEQ_editing_get(scene); + + if (seq == NULL) { + return false; + } + + if (RNA_boolean_get(op->ptr, "replace_sel")) { + seq->flag |= SELECT; + SEQ_select_active_set(scene, seq); + } + + SEQ_collection_append_strip(seq, strip_col); + + return SEQ_transform_test_overlap(ed->seqbasep, seq); +} + static bool seq_effect_add_properties_poll(const bContext *UNUSED(C), wmOperator *op, const PropertyRNA *prop) @@ -634,6 +685,14 @@ static void sequencer_add_movie_multiple_strips(bContext *C, Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); const Editing *ed = SEQ_editing_ensure(scene); + bool overlap_shuffle_override = RNA_boolean_get(op->ptr, "overlap") == false && + RNA_boolean_get(op->ptr, "overlap_shuffle_override"); + bool has_seq_overlap = false; + SeqCollection *strip_col = NULL; + + if (overlap_shuffle_override) { + strip_col = SEQ_collection_create(__func__); + } RNA_BEGIN (op->ptr, itemptr, "files") { char dir_only[FILE_MAX]; @@ -645,9 +704,8 @@ static void sequencer_add_movie_multiple_strips(bContext *C, Sequence *seq_movie = NULL; Sequence *seq_sound = NULL; - load_data->channel++; seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data); - load_data->channel--; + if (seq_movie == NULL) { BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path); } @@ -655,15 +713,40 @@ static void sequencer_add_movie_multiple_strips(bContext *C, if (RNA_boolean_get(op->ptr, "sound")) { seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound); + + if (seq_sound) { + /* The video has sound, shift the video strip up a channel to make room for the sound + * strip. */ + seq_movie->machine++; + } } load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp; - seq_load_apply_generic_options(C, op, seq_sound); - seq_load_apply_generic_options(C, op, seq_movie); + if (overlap_shuffle_override) { + has_seq_overlap |= seq_load_apply_generic_options_only_test_overlap( + C, op, seq_sound, strip_col); + has_seq_overlap |= seq_load_apply_generic_options_only_test_overlap( + C, op, seq_movie, strip_col); + } + else { + seq_load_apply_generic_options(C, op, seq_sound); + seq_load_apply_generic_options(C, op, seq_movie); + } SEQ_collection_append_strip(seq_movie, r_movie_strips); } } RNA_END; + + if (overlap_shuffle_override) { + if (has_seq_overlap) { + ScrArea *area = CTX_wm_area(C); + const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag & + SEQ_MARKER_TRANS) != 0; + SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers); + } + + SEQ_collection_free(strip_col); + } } static bool sequencer_add_movie_single_strip(bContext *C, @@ -678,9 +761,7 @@ static bool sequencer_add_movie_single_strip(bContext *C, Sequence *seq_movie = NULL; Sequence *seq_sound = NULL; - load_data->channel++; seq_movie = SEQ_add_movie_strip(bmain, scene, ed->seqbasep, load_data); - load_data->channel--; if (seq_movie == NULL) { BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path); @@ -689,9 +770,37 @@ static bool sequencer_add_movie_single_strip(bContext *C, if (RNA_boolean_get(op->ptr, "sound")) { seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data); sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound); + if (seq_sound) { + /* The video has sound, shift the video strip up a channel to make room for the sound + * strip. */ + seq_movie->machine++; + } + } + + bool overlap_shuffle_override = RNA_boolean_get(op->ptr, "overlap") == false && + RNA_boolean_get(op->ptr, "overlap_shuffle_override"); + if (overlap_shuffle_override) { + SeqCollection *strip_col = SEQ_collection_create(__func__); + bool has_seq_overlap = false; + + has_seq_overlap |= seq_load_apply_generic_options_only_test_overlap( + C, op, seq_sound, strip_col); + has_seq_overlap |= seq_load_apply_generic_options_only_test_overlap( + C, op, seq_movie, strip_col); + + if (has_seq_overlap) { + ScrArea *area = CTX_wm_area(C); + const bool use_sync_markers = (((SpaceSeq *)area->spacedata.first)->flag & + SEQ_MARKER_TRANS) != 0; + SEQ_transform_handle_overlap(scene, ed->seqbasep, strip_col, use_sync_markers); + } + + SEQ_collection_free(strip_col); + } + else { + seq_load_apply_generic_options(C, op, seq_sound); + seq_load_apply_generic_options(C, op, seq_movie); } - seq_load_apply_generic_options(C, op, seq_sound); - seq_load_apply_generic_options(C, op, seq_movie); SEQ_collection_append_strip(seq_movie, r_movie_strips); return true; diff --git a/source/blender/editors/space_sequencer/sequencer_drag_drop.c b/source/blender/editors/space_sequencer/sequencer_drag_drop.c new file mode 100644 index 00000000000..639d3651714 --- /dev/null +++ b/source/blender/editors/space_sequencer/sequencer_drag_drop.c @@ -0,0 +1,650 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup spseq + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_scene_types.h" +#include "DNA_sound_types.h" + +#include "BLI_blenlib.h" +#include "BLI_string_utils.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_image.h" +#include "BKE_main.h" + +#include "SEQ_channels.h" +#include "SEQ_iterator.h" +#include "SEQ_sequencer.h" +#include "SEQ_transform.h" + +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "GPU_immediate.h" +#include "GPU_matrix.h" + +#include "ED_screen.h" +#include "ED_transform.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "WM_api.h" +#include "WM_types.h" + +/* For querying audio files. */ +#ifdef WITH_AUDASPACE +# include "BKE_sound.h" +# include <AUD_Sound.h> +# include <AUD_Special.h> +#endif + +/* Own include. */ +#include "sequencer_intern.h" + +typedef struct SeqDropCoords { + float start_frame, channel; + int strip_len, channel_len; + bool in_use; + bool is_intersecting; + bool use_snapping; + float snap_point_x; + uint8_t type; +} SeqDropCoords; + +/* The current drag and drop API doesn't allow us to easily pass along the + * required custom data to all callbacks that need it. Especially when + * preloading data on drag start. + * Therefore we will for now use a global variable for this. + */ +static SeqDropCoords g_drop_coords = {.in_use = false}; + +static void generic_poll_operations(const wmEvent *event, uint8_t type) +{ + g_drop_coords.type = type; + /* We purposely ignore the snapping tool setting here as currently other drag&drop operators only + * snaps when holding down Ctrl. */ + g_drop_coords.use_snapping = event->modifier & KM_CTRL; +} + +static bool image_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *event) +{ + if (drag->type == WM_DRAG_PATH) { + if (ELEM(drag->icon, ICON_FILE_IMAGE, ICON_FILE_BLANK)) { /* Rule might not work? */ + generic_poll_operations(event, TH_SEQ_IMAGE); + return true; + } + } + + return WM_drag_is_ID_type(drag, ID_IM); +} + +static bool movie_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *event) +{ + if (drag->type == WM_DRAG_PATH) { + if (ELEM(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) { /* Rule might not work? */ + generic_poll_operations(event, TH_SEQ_MOVIE); + return true; + } + } + + return WM_drag_is_ID_type(drag, ID_MC); +} + +static bool sound_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *event) +{ + if (drag->type == WM_DRAG_PATH) { + if (ELEM(drag->icon, ICON_FILE_SOUND, ICON_FILE_BLANK)) { /* Rule might not work? */ + generic_poll_operations(event, TH_SEQ_AUDIO); + return true; + } + } + + return WM_drag_is_ID_type(drag, ID_SO); +} + +static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop) +{ + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); + /* ID dropped. */ + if (id != NULL) { + const ID_Type id_type = GS(id->name); + if (id_type == ID_IM) { + Image *ima = (Image *)id; + PointerRNA itemptr; + char dir[FILE_MAX], file[FILE_MAX]; + BLI_split_dirfile(ima->filepath, dir, file, sizeof(dir), sizeof(file)); + RNA_string_set(drop->ptr, "directory", dir); + RNA_collection_clear(drop->ptr, "files"); + RNA_collection_add(drop->ptr, "files", &itemptr); + RNA_string_set(&itemptr, "name", file); + } + else if (id_type == ID_MC) { + MovieClip *clip = (MovieClip *)id; + RNA_string_set(drop->ptr, "filepath", clip->filepath); + RNA_struct_property_unset(drop->ptr, "name"); + } + else if (id_type == ID_SO) { + bSound *sound = (bSound *)id; + RNA_string_set(drop->ptr, "filepath", sound->filepath); + RNA_struct_property_unset(drop->ptr, "name"); + } + } + /* Path dropped. */ + else if (drag->path[0]) { + if (RNA_struct_find_property(drop->ptr, "filepath")) { + RNA_string_set(drop->ptr, "filepath", drag->path); + } + if (RNA_struct_find_property(drop->ptr, "directory")) { + PointerRNA itemptr; + char dir[FILE_MAX], file[FILE_MAX]; + + BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file)); + + RNA_string_set(drop->ptr, "directory", dir); + + RNA_collection_clear(drop->ptr, "files"); + RNA_collection_add(drop->ptr, "files", &itemptr); + RNA_string_set(&itemptr, "name", file); + } + + if (g_drop_coords.in_use) { + RNA_int_set(drop->ptr, "frame_start", g_drop_coords.start_frame); + RNA_int_set(drop->ptr, "channel", g_drop_coords.channel); + RNA_boolean_set(drop->ptr, "overlap_shuffle_override", true); + } + else { + Scene *scene = CTX_data_scene(C); + Editing *ed = SEQ_editing_get(scene); + ListBase *seqbase = SEQ_active_seqbase_get(ed); + ListBase *channels = SEQ_channels_displayed_get(ed); + SpaceSeq *sseq = CTX_wm_space_seq(C); + + SeqCollection *strips = SEQ_query_rendered_strips( + channels, seqbase, scene->r.cfra, sseq->chanshown); + + /* Get the top most strip channel that is in view.*/ + Sequence *seq; + int max_channel = -1; + SEQ_ITERATOR_FOREACH (seq, strips) { + max_channel = max_ii(seq->machine, max_channel); + } + + if (max_channel != -1) { + RNA_int_set(drop->ptr, "channel", max_channel); + } + } + } +} + +static void update_overlay_strip_poistion_data(bContext *C, const int mval[2]) +{ + SeqDropCoords *coords = &g_drop_coords; + ARegion *region = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + int hand; + View2D *v2d = ®ion->v2d; + + /* Update the position were we would place the strip if we complete the drag and drop action. + */ + UI_view2d_region_to_view(v2d, mval[0], mval[1], &coords->start_frame, &coords->channel); + coords->start_frame = roundf(coords->start_frame); + if (coords->channel < 1.0f) { + coords->channel = 1; + } + + float start_frame = coords->start_frame; + float end_frame = coords->start_frame + coords->strip_len; + + if (coords->use_snapping) { + /* Do snapping via the exsiting transform code. */ + int snap_delta; + float snap_frame; + bool valid_snap; + + valid_snap = ED_transform_snap_sequencer_to_closest_strip_calc( + scene, region, start_frame, end_frame, &snap_delta, &snap_frame); + + if (valid_snap) { + /* We snapped onto something! */ + start_frame += snap_delta; + coords->start_frame = start_frame; + end_frame = start_frame + coords->strip_len; + coords->snap_point_x = snap_frame; + } + else { + /* Nothing was snapped to, disable snap drawing. */ + coords->use_snapping = false; + } + } + + if (coords->strip_len < 1) { + /* Only check if there is a strip already under the mouse cursor. */ + coords->is_intersecting = find_nearest_seq(scene, ®ion->v2d, &hand, mval); + } + else { + /* Check if there is a strip that would intersect with the new strip(s). */ + coords->is_intersecting = false; + Sequence dummy_seq = {.machine = coords->channel, + .startdisp = coords->start_frame, + .enddisp = coords->start_frame + coords->strip_len}; + Editing *ed = SEQ_editing_get(scene); + + for (int i = 0; i < coords->channel_len && !coords->is_intersecting; i++) { + coords->is_intersecting = SEQ_transform_test_overlap(ed->seqbasep, &dummy_seq); + dummy_seq.machine++; + } + } +} + +static void draw_seq_in_view(bContext *C, wmWindow *UNUSED(win), wmDrag *drag, const int xy[2]) +{ + SeqDropCoords *coords = &g_drop_coords; + if (!coords->in_use) { + return; + } + + ARegion *region = CTX_wm_region(C); + int mval[2]; + /* Convert mouse coordinates to region local coordinates. */ + mval[0] = xy[0] - region->winrct.xmin; + mval[1] = xy[1] - region->winrct.ymin; + + update_overlay_strip_poistion_data(C, mval); + + GPU_matrix_push(); + UI_view2d_view_ortho(®ion->v2d); + + /* Sometimes the active theme is not the sequencer theme, e.g. when an operator invokes the + * file browser. This makes sure we get the right color values for the theme. */ + struct bThemeState theme_state; + UI_Theme_Store(&theme_state); + UI_SetTheme(SPACE_SEQ, RGN_TYPE_WINDOW); + + if (coords->use_snapping) { + ED_draw_sequencer_snap_point(C, coords->snap_point_x); + } + + /* Init GPU drawing. */ + GPU_line_width(2.0f); + GPU_blend(GPU_BLEND_ALPHA); + GPU_line_smooth(true); + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + + /* Draw strips. The code here is taken from sequencer_draw. */ + float x1 = coords->start_frame; + float x2 = coords->start_frame + coords->strip_len; + float strip_color[3]; + uchar text_color[4] = {255, 255, 255, 255}; + float pixelx = BLI_rctf_size_x(®ion->v2d.cur) / BLI_rcti_size_x(®ion->v2d.mask); + float pixely = BLI_rctf_size_y(®ion->v2d.cur) / BLI_rcti_size_y(®ion->v2d.mask); + + for (int i = 0; i < coords->channel_len; i++) { + float y1 = floorf(coords->channel) + i + SEQ_STRIP_OFSBOTTOM; + float y2 = floorf(coords->channel) + i + SEQ_STRIP_OFSTOP; + + if (coords->type == TH_SEQ_MOVIE && i == 0 && coords->channel_len > 1) { + /* Assume only video strips occupies two channels. + * One for video and the other for audio. + * The audio channel is added first. + */ + UI_GetThemeColor3fv(TH_SEQ_AUDIO, strip_color); + } + else { + UI_GetThemeColor3fv(coords->type, strip_color); + } + + immUniformColor3fvAlpha(strip_color, 0.8f); + immRectf(pos, x1, y1, x2, y2); + + if (coords->is_intersecting) { + strip_color[0] = 1.0f; + strip_color[1] = strip_color[2] = 0.3f; + } + else { + if (coords->channel_len - 1 == i) { + text_color[0] = text_color[1] = text_color[2] = 255; + UI_GetThemeColor3fv(TH_SEQ_ACTIVE, strip_color); + } + else { + text_color[0] = text_color[1] = text_color[2] = 10; + UI_GetThemeColor3fv(TH_SEQ_SELECTED, strip_color); + } + } + + /* Draw a 2 pixel border around the strip. */ + immUniformColor3fvAlpha(strip_color, 0.8f); + /* Left */ + immRectf(pos, x1 - pixelx, y1, x1 + pixelx, y2); + /* Bottom */ + immRectf(pos, x1 - pixelx, y1, x2 + pixelx, y1 + 2 * pixely); + /* Right */ + immRectf(pos, x2 - pixelx, y1, x2 + pixelx, y2); + /* Top */ + immRectf(pos, x1 - pixelx, y2 - 2 * pixely, x2 + pixelx, y2); + + float handle_size = 8.0f; /* SEQ_HANDLE_SIZE */ + + /* Calculate height needed for drawing text on strip. */ + float text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely); + float text_margin_x = 2.0f * (pixelx * handle_size) * U.pixelsize; + + rctf rect; + rect.xmin = x1 + text_margin_x; + rect.ymin = text_margin_y; + rect.xmax = x2 - text_margin_x; + rect.ymax = y2; + + if (rect.xmax <= rect.xmin) { + /* Exit early and skip text drawing if the strip doesn't have any space to put the text + * into. + */ + break; + } + + SpaceSeq *sseq = CTX_wm_space_seq(C); + const char *text_sep = " | "; + const char *text_array[5]; + char text_display[FILE_MAX]; + char filename[FILE_MAX]; + char rel_path[FILE_MAX]; + char strip_duration_text[16]; + int len_text_arr = 0; + + if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_NAME) { + BLI_split_file_part(drag->path, filename, FILE_MAX); + text_array[len_text_arr++] = filename; + } + + if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_SOURCE) { + Main *bmain = CTX_data_main(C); + BLI_strncpy(rel_path, drag->path, FILE_MAX); + BLI_path_rel(rel_path, BKE_main_blendfile_path(bmain)); + text_array[len_text_arr++] = text_sep; + text_array[len_text_arr++] = rel_path; + } + + if (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_STRIP_DURATION) { + SNPRINTF(strip_duration_text, "%d", (int)(x2 - x1)); + text_array[len_text_arr++] = text_sep; + text_array[len_text_arr++] = strip_duration_text; + } + + BLI_assert(len_text_arr <= ARRAY_SIZE(text_array)); + + BLI_string_join_array(text_display, FILE_MAX, text_array, len_text_arr); + + UI_view2d_text_cache_add_rectf( + ®ion->v2d, &rect, text_display, strlen(text_display), text_color); + } + + /* Clean after drawing up. */ + UI_Theme_Restore(&theme_state); + GPU_matrix_pop(); + immUnbindProgram(); + GPU_blend(GPU_BLEND_NONE); + GPU_line_smooth(false); + + UI_view2d_text_cache_draw(region); +} + +static bool generic_drop_draw_handling(struct wmDropBox *drop) +{ + SeqDropCoords *coords = drop->draw_data; + if (coords && coords->in_use) { + return true; + } + + coords = drop->draw_data = &g_drop_coords; + coords->in_use = true; + + return false; +} + +typedef struct DropJobData { + char path[FILE_MAX]; + bool only_audio; + float scene_fps; +} DropJobData; + +static void prefetch_data_fn(void *custom_data, + short *UNUSED(stop), + short *UNUSED(do_update), + float *UNUSED(progress)) +{ + DropJobData *job_data = (DropJobData *)custom_data; + + if (job_data->only_audio) { +#ifdef WITH_AUDASPACE + /* Get the sound file length */ + AUD_Sound *sound = AUD_Sound_file(job_data->path); + if (sound != NULL) { + + AUD_SoundInfo info = AUD_getInfo(sound); + if ((eSoundChannels)info.specs.channels != SOUND_CHANNELS_INVALID) { + g_drop_coords.strip_len = max_ii(1, round((info.length) * job_data->scene_fps)); + } + AUD_Sound_free(sound); + return; + } +#endif + } + + char colorspace[64] = "\0"; /* 64 == MAX_COLORSPACE_NAME length. */ + struct anim *anim = openanim(job_data->path, IB_rect, 0, colorspace); + + if (anim != NULL) { + g_drop_coords.strip_len = IMB_anim_get_duration(anim, IMB_TC_NONE); + IMB_free_anim(anim); +#ifdef WITH_AUDASPACE + /* Try to load sound and see if the video has a sound channel. */ + AUD_Sound *sound = AUD_Sound_file(job_data->path); + if (sound != NULL) { + + AUD_SoundInfo info = AUD_getInfo(sound); + if ((eSoundChannels)info.specs.channels != SOUND_CHANNELS_INVALID) { + g_drop_coords.channel_len = 2; + } + AUD_Sound_free(sound); + } +#endif + } +} + +static void free_prefetch_data_fn(void *custom_data) +{ + DropJobData *job_data = (DropJobData *)custom_data; + MEM_freeN(job_data); +} + +static void start_audio_video_job(bContext *C, char *path, bool only_audio) +{ + g_drop_coords.strip_len = 0; + g_drop_coords.channel_len = 1; + + wmWindowManager *wm = CTX_wm_manager(C); + wmWindow *win = CTX_wm_window(C); + Scene *scene = CTX_data_scene(C); + + wmJob *wm_job = WM_jobs_get( + wm, win, NULL, "Load Previews", 0, WM_JOB_TYPE_SEQ_DRAG_DROP_PREVIEW); + + DropJobData *job_data = (DropJobData *)MEM_mallocN(sizeof(DropJobData), + "SeqDragDropPreviewData"); + + BLI_strncpy(job_data->path, path, FILE_MAX); + job_data->only_audio = only_audio; + job_data->scene_fps = FPS; + + WM_jobs_customdata_set(wm_job, job_data, free_prefetch_data_fn); + WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW); + WM_jobs_callbacks(wm_job, prefetch_data_fn, NULL, NULL, NULL); + + WM_jobs_start(wm, wm_job); +} + +static void video_prefetch(bContext *C, wmDrag *drag) +{ + if (drag->type == WM_DRAG_PATH && ELEM(drag->icon, ICON_FILE_MOVIE, ICON_FILE_BLANK)) { + start_audio_video_job(C, drag->path, false); + } +} + +static void audio_prefetch(bContext *C, wmDrag *drag) +{ + if (drag->type == WM_DRAG_PATH && ELEM(drag->icon, ICON_FILE_SOUND, ICON_FILE_BLANK)) { + start_audio_video_job(C, drag->path, true); + } +} + +static void movie_drop_draw_activate(struct wmDropBox *drop, wmDrag *UNUSED(drag)) +{ + if (generic_drop_draw_handling(drop)) { + return; + } +} + +static void sound_drop_draw_activate(struct wmDropBox *drop, wmDrag *UNUSED(drag)) +{ + if (generic_drop_draw_handling(drop)) { + return; + } +} + +static void image_drop_draw_activate(struct wmDropBox *drop, wmDrag *UNUSED(drag)) +{ + if (generic_drop_draw_handling(drop)) { + return; + } + + SeqDropCoords *coords = drop->draw_data; + coords->strip_len = DEFAULT_IMG_STRIP_LENGTH; + coords->channel_len = 1; +} + +static void sequencer_drop_draw_deactivate(struct wmDropBox *drop, wmDrag *UNUSED(drag)) +{ + SeqDropCoords *coords = drop->draw_data; + if (coords) { + coords->in_use = false; + drop->draw_data = NULL; + } +} + +static void nop_draw_droptip_fn(bContext *UNUSED(C), + wmWindow *UNUSED(win), + wmDrag *UNUSED(drag), + const int UNUSED(xy[2])) +{ + /* Do nothing in here. + * This is to prevent the default drag and drop mouse overlay to be drawn. + */ +} + +/* This region dropbox definition. */ +static void sequencer_dropboxes_add_to_lb(ListBase *lb) +{ + struct wmDropBox *drop; + drop = WM_dropbox_add( + lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy, NULL, NULL); + drop->draw_droptip = nop_draw_droptip_fn; + drop->draw_in_view = draw_seq_in_view; + drop->draw_activate = image_drop_draw_activate; + drop->draw_deactivate = sequencer_drop_draw_deactivate; + + drop->on_drag_start = audio_prefetch; + + drop = WM_dropbox_add( + lb, "SEQUENCER_OT_movie_strip_add", movie_drop_poll, sequencer_drop_copy, NULL, NULL); + drop->draw_droptip = nop_draw_droptip_fn; + drop->draw_in_view = draw_seq_in_view; + drop->draw_activate = movie_drop_draw_activate; + drop->draw_deactivate = sequencer_drop_draw_deactivate; + + drop->on_drag_start = video_prefetch; + + drop = WM_dropbox_add( + lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy, NULL, NULL); + drop->draw_droptip = nop_draw_droptip_fn; + drop->draw_in_view = draw_seq_in_view; + drop->draw_activate = sound_drop_draw_activate; + drop->draw_deactivate = sequencer_drop_draw_deactivate; +} + +static bool image_drop_preview_poll(bContext *UNUSED(C), + wmDrag *drag, + const wmEvent *UNUSED(event)) +{ + if (drag->type == WM_DRAG_PATH) { + if (ELEM(drag->icon, ICON_FILE_IMAGE, ICON_FILE_BLANK)) { /* Rule might not work? */ + return true; + } + } + + return WM_drag_is_ID_type(drag, ID_IM); +} + +static bool movie_drop_preview_poll(bContext *UNUSED(C), + wmDrag *drag, + const wmEvent *UNUSED(event)) +{ + if (drag->type == WM_DRAG_PATH) { + if (ELEM(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) { /* Rule might not work? */ + return true; + } + } + + return WM_drag_is_ID_type(drag, ID_MC); +} + +static bool sound_drop_preview_poll(bContext *UNUSED(C), + wmDrag *drag, + const wmEvent *UNUSED(event)) +{ + if (drag->type == WM_DRAG_PATH) { + if (ELEM(drag->icon, ICON_FILE_SOUND, ICON_FILE_BLANK)) { /* Rule might not work? */ + return true; + } + } + + return WM_drag_is_ID_type(drag, ID_SO); +} + +static void sequencer_preview_dropboxes_add_to_lb(ListBase *lb) +{ + WM_dropbox_add(lb, + "SEQUENCER_OT_image_strip_add", + image_drop_preview_poll, + sequencer_drop_copy, + NULL, + NULL); + + WM_dropbox_add(lb, + "SEQUENCER_OT_movie_strip_add", + movie_drop_preview_poll, + sequencer_drop_copy, + NULL, + NULL); + + WM_dropbox_add(lb, + "SEQUENCER_OT_sound_strip_add", + sound_drop_preview_poll, + sequencer_drop_copy, + NULL, + NULL); +} + +void sequencer_dropboxes(void) +{ + ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); + sequencer_dropboxes_add_to_lb(lb); + lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW); + sequencer_preview_dropboxes_add_to_lb(lb); +} diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 781aa521880..67df065ef35 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -29,6 +29,7 @@ struct ScrArea; struct Editing; struct ListBase; +#define DEFAULT_IMG_STRIP_LENGTH 25 /* XXX arbitrary but ok for now. */ #define OVERLAP_ALPHA 180 typedef struct SeqChannelDrawContext { @@ -237,6 +238,10 @@ void SEQUENCER_OT_sound_strip_add(struct wmOperatorType *ot); void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot); void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot); +/* sequencer_drag_drop.c */ + +void sequencer_dropboxes(void); + /* sequencer_ops.c */ void sequencer_operatortypes(void); diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 89bff839481..ed669f5f8d2 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -9,20 +9,15 @@ #include <stdio.h> #include <string.h> -#include "DNA_gpencil_types.h" #include "DNA_mask_types.h" #include "DNA_scene_types.h" -#include "DNA_sound_types.h" #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_ghash.h" -#include "BLI_utildefines.h" -#include "BKE_context.h" #include "BKE_global.h" -#include "BKE_lib_id.h" #include "BKE_lib_remap.h" #include "BKE_screen.h" #include "BKE_sequencer_offscreen.h" @@ -37,15 +32,11 @@ #include "WM_api.h" #include "WM_message.h" -#include "WM_types.h" - -#include "RNA_access.h" #include "SEQ_transform.h" #include "SEQ_utils.h" #include "UI_interface.h" -#include "UI_resources.h" #include "UI_view2d.h" #include "IMB_imbuf.h" @@ -404,128 +395,6 @@ static void sequencer_listener(const wmSpaceTypeListenerParams *params) } } -/* ************* dropboxes ************* */ - -static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) -{ - ARegion *region = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - int hand; - - if (drag->type == WM_DRAG_PATH) { - if (ELEM(drag->icon, ICON_FILE_IMAGE, ICON_FILE_BLANK)) { /* Rule might not work? */ - if (find_nearest_seq(scene, ®ion->v2d, &hand, event->mval) == NULL) { - return 1; - } - } - } - - return WM_drag_is_ID_type(drag, ID_IM); -} - -static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) -{ - ARegion *region = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - int hand; - - if (drag->type == WM_DRAG_PATH) { - if (ELEM(drag->icon, 0, ICON_FILE_MOVIE, ICON_FILE_BLANK)) { /* Rule might not work? */ - if (find_nearest_seq(scene, ®ion->v2d, &hand, event->mval) == NULL) { - return 1; - } - } - } - - return WM_drag_is_ID_type(drag, ID_MC); -} - -static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) -{ - ARegion *region = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - int hand; - - if (drag->type == WM_DRAG_PATH) { - if (ELEM(drag->icon, ICON_FILE_SOUND, ICON_FILE_BLANK)) { /* Rule might not work? */ - if (find_nearest_seq(scene, ®ion->v2d, &hand, event->mval) == NULL) { - return 1; - } - } - } - - return WM_drag_is_ID_type(drag, ID_SO); -} - -static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop) -{ - ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); - /* ID dropped. */ - if (id != NULL) { - const ID_Type id_type = GS(id->name); - if (id_type == ID_IM) { - Image *ima = (Image *)id; - PointerRNA itemptr; - char dir[FILE_MAX], file[FILE_MAX]; - BLI_split_dirfile(ima->filepath, dir, file, sizeof(dir), sizeof(file)); - RNA_string_set(drop->ptr, "directory", dir); - RNA_collection_clear(drop->ptr, "files"); - RNA_collection_add(drop->ptr, "files", &itemptr); - RNA_string_set(&itemptr, "name", file); - } - else if (id_type == ID_MC) { - MovieClip *clip = (MovieClip *)id; - RNA_string_set(drop->ptr, "filepath", clip->filepath); - RNA_struct_property_unset(drop->ptr, "name"); - } - else if (id_type == ID_SO) { - bSound *sound = (bSound *)id; - RNA_string_set(drop->ptr, "filepath", sound->filepath); - RNA_struct_property_unset(drop->ptr, "name"); - } - } - /* Path dropped. */ - else if (drag->path[0]) { - if (RNA_struct_find_property(drop->ptr, "filepath")) { - RNA_string_set(drop->ptr, "filepath", drag->path); - } - if (RNA_struct_find_property(drop->ptr, "directory")) { - PointerRNA itemptr; - char dir[FILE_MAX], file[FILE_MAX]; - - BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file)); - - RNA_string_set(drop->ptr, "directory", dir); - - RNA_collection_clear(drop->ptr, "files"); - RNA_collection_add(drop->ptr, "files", &itemptr); - RNA_string_set(&itemptr, "name", file); - } - } -} - -/* This region dropbox definition. */ - -static void sequencer_dropboxes_add_to_lb(ListBase *lb) -{ - WM_dropbox_add( - lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy, NULL, NULL); - WM_dropbox_add( - lb, "SEQUENCER_OT_movie_strip_add", movie_drop_poll, sequencer_drop_copy, NULL, NULL); - WM_dropbox_add( - lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy, NULL, NULL); -} - -static void sequencer_dropboxes(void) -{ - ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); - sequencer_dropboxes_add_to_lb(lb); - lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW); - sequencer_dropboxes_add_to_lb(lb); -} - -/* ************* end drop *********** */ - /* DO NOT make this static, this hides the symbol and breaks API generation script. */ extern const char *sequencer_context_dir[]; /* Quiet warning. */ const char *sequencer_context_dir[] = {"edit_mask", NULL}; diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index 15353d610d1..ea35a8c0fa7 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -308,7 +308,7 @@ static bool text_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNU return false; } -static void text_drop_copy(wmDrag *drag, wmDropBox *drop) +static void text_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { /* copy drag path to properties */ RNA_string_set(drop->ptr, "filepath", drag->path); @@ -319,7 +319,7 @@ static bool text_drop_paste_poll(bContext *UNUSED(C), wmDrag *drag, const wmEven return (drag->type == WM_DRAG_ID); } -static void text_drop_paste(wmDrag *drag, wmDropBox *drop) +static void text_drop_paste(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { char *text; ID *id = WM_drag_get_local_ID(drag, 0); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 1d22c2f237b..50d288af0e0 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -712,7 +712,7 @@ static void view3d_ob_drop_matrix_from_snap(V3DSnapCursorState *snap_state, } } -static void view3d_ob_drop_copy_local_id(wmDrag *drag, wmDropBox *drop) +static void view3d_ob_drop_copy_local_id(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { ID *id = WM_drag_get_local_ID(drag, ID_OB); @@ -730,7 +730,7 @@ static void view3d_ob_drop_copy_local_id(wmDrag *drag, wmDropBox *drop) /* Mostly the same logic as #view3d_collection_drop_copy_external_asset(), just different enough to * make sharing code a bit difficult. */ -static void view3d_ob_drop_copy_external_asset(wmDrag *drag, wmDropBox *drop) +static void view3d_ob_drop_copy_external_asset(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { /* NOTE(@campbellbarton): Selection is handled here, de-selecting objects before append, * using auto-select to ensure the new objects are selected. @@ -771,7 +771,9 @@ static void view3d_ob_drop_copy_external_asset(wmDrag *drag, wmDropBox *drop) } } -static void view3d_collection_drop_copy_local_id(wmDrag *drag, wmDropBox *drop) +static void view3d_collection_drop_copy_local_id(bContext *UNUSED(C), + wmDrag *drag, + wmDropBox *drop) { ID *id = WM_drag_get_local_ID(drag, ID_GR); RNA_int_set(drop->ptr, "session_uuid", (int)id->session_uuid); @@ -779,7 +781,9 @@ static void view3d_collection_drop_copy_local_id(wmDrag *drag, wmDropBox *drop) /* Mostly the same logic as #view3d_ob_drop_copy_external_asset(), just different enough to make * sharing code a bit difficult. */ -static void view3d_collection_drop_copy_external_asset(wmDrag *drag, wmDropBox *drop) +static void view3d_collection_drop_copy_external_asset(bContext *UNUSED(C), + wmDrag *drag, + wmDropBox *drop) { BLI_assert(drag->type == WM_DRAG_ASSET); @@ -815,14 +819,14 @@ static void view3d_collection_drop_copy_external_asset(wmDrag *drag, wmDropBox * ED_undo_push(C, "Collection_Drop"); } -static void view3d_id_drop_copy(wmDrag *drag, wmDropBox *drop) +static void view3d_id_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); RNA_string_set(drop->ptr, "name", id->name + 2); } -static void view3d_id_drop_copy_with_type(wmDrag *drag, wmDropBox *drop) +static void view3d_id_drop_copy_with_type(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); @@ -830,7 +834,7 @@ static void view3d_id_drop_copy_with_type(wmDrag *drag, wmDropBox *drop) RNA_enum_set(drop->ptr, "type", GS(id->name)); } -static void view3d_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) +static void view3d_id_path_drop_copy(bContext *UNUSED(C), wmDrag *drag, wmDropBox *drop) { ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); @@ -878,7 +882,7 @@ static void view3d_dropboxes(void) WM_drag_free_imported_drag_ID, NULL); - drop->draw = WM_drag_draw_item_name_fn; + drop->draw_droptip = WM_drag_draw_item_name_fn; drop->draw_activate = view3d_ob_drop_draw_activate; drop->draw_deactivate = view3d_ob_drop_draw_deactivate; @@ -889,7 +893,7 @@ static void view3d_dropboxes(void) WM_drag_free_imported_drag_ID, NULL); - drop->draw = WM_drag_draw_item_name_fn; + drop->draw_droptip = WM_drag_draw_item_name_fn; drop->draw_activate = view3d_ob_drop_draw_activate; drop->draw_deactivate = view3d_ob_drop_draw_deactivate; diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 68c9a1c23c3..a3df6a44682 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -11,8 +11,6 @@ #include "ED_transform.h" #include "ED_view3d.h" -#include "RE_engine.h" - #include "DNA_listBase.h" #include "DNA_object_enums.h" diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 2b338f6ad08..7080deaec66 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -8,6 +8,8 @@ #pragma once +#include "RE_engine.h" + struct BMEditMesh; struct BMesh; struct BezTriple; diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index d7d85646b08..c1e8dab3b3e 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -326,13 +326,14 @@ static SeqCollection *query_right_side_strips(ListBase *seqbase, SeqCollection * return collection; } -static void seq_transform_update_effects(TransInfo *t, SeqCollection *collection) +static void seq_transform_update_effects(Scene *scene, + ListBase *seqbasep, + SeqCollection *collection) { Sequence *seq; SEQ_ITERATOR_FOREACH (seq, collection) { if ((seq->type & SEQ_TYPE_EFFECT) && (seq->seq1 || seq->seq2 || seq->seq3)) { - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene)); - SEQ_time_update_sequence(t->scene, seqbase, seq); + SEQ_time_update_sequence(scene, seqbasep, seq); } } } @@ -357,12 +358,12 @@ static ListBase *seqbase_active_get(const TransInfo *t) /* Offset all strips positioned after left edge of transformed strips bound-box by amount equal * to overlap of transformed strips. */ -static void seq_transform_handle_expand_to_fit(TransInfo *t, SeqCollection *transformed_strips) +static void seq_transform_handle_expand_to_fit(Scene *scene, + ListBase *seqbasep, + SeqCollection *transformed_strips, + bool use_sync_markers) { - ListBase *seqbasep = seqbase_active_get(t); - ListBase *markers = &t->scene->markers; - const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag & - SEQ_MARKER_TRANS) != 0; + ListBase *markers = &scene->markers; SeqCollection *right_side_strips = query_right_side_strips(seqbasep, transformed_strips); @@ -376,7 +377,7 @@ static void seq_transform_handle_expand_to_fit(TransInfo *t, SeqCollection *tran * strips on left side. */ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips); SEQ_transform_seqbase_shuffle_time( - standalone_strips, seqbasep, t->scene, markers, use_sync_markers); + standalone_strips, seqbasep, scene, markers, use_sync_markers); SEQ_collection_free(standalone_strips); /* Move temporarily moved strips back to their original place and tag for shuffling. */ @@ -384,17 +385,17 @@ static void seq_transform_handle_expand_to_fit(TransInfo *t, SeqCollection *tran seq->machine -= MAXSEQ * 2; } /* Shuffle again to displace strips on right side. Final effect shuffling is done in - * seq_transform_handle_overlap. */ + * SEQ_transform_handle_overlap. */ SEQ_transform_seqbase_shuffle_time( - right_side_strips, seqbasep, t->scene, markers, use_sync_markers); - seq_transform_update_effects(t, right_side_strips); + right_side_strips, seqbasep, scene, markers, use_sync_markers); + seq_transform_update_effects(scene, seqbasep, right_side_strips); SEQ_collection_free(right_side_strips); } -static SeqCollection *query_overwrite_targets(const TransInfo *t, +static SeqCollection *query_overwrite_targets(ListBase *seqbasep, SeqCollection *transformed_strips) { - SeqCollection *collection = SEQ_query_unselected_strips(seqbase_active_get(t)); + SeqCollection *collection = SEQ_query_unselected_strips(seqbasep); Sequence *seq, *seq_transformed; SEQ_ITERATOR_FOREACH (seq, collection) { @@ -449,35 +450,36 @@ static eOvelapDescrition overlap_description_get(const Sequence *transformed, } /* Split strip in 3 parts, remove middle part and fit transformed inside. */ -static void seq_transform_handle_overwrite_split(const TransInfo *t, +static void seq_transform_handle_overwrite_split(Scene *scene, + ListBase *seqbasep, const Sequence *transformed, Sequence *target) { - Main *bmain = CTX_data_main(t->context); - Scene *scene = t->scene; - ListBase *seqbase = seqbase_active_get(t); + /* Because we are doing a soft split, bmain is not used in SEQ_edit_strip_split, so we can pass + * NULL here. */ + Main *bmain = NULL; Sequence *split_strip = SEQ_edit_strip_split( - bmain, scene, seqbase, target, transformed->startdisp, SEQ_SPLIT_SOFT, NULL); + bmain, scene, seqbasep, target, transformed->startdisp, SEQ_SPLIT_SOFT, NULL); SEQ_edit_strip_split( - bmain, scene, seqbase, split_strip, transformed->enddisp, SEQ_SPLIT_SOFT, NULL); - SEQ_edit_flag_for_removal(scene, seqbase_active_get(t), split_strip); - SEQ_edit_remove_flagged_sequences(t->scene, seqbase_active_get(t)); + bmain, scene, seqbasep, split_strip, transformed->enddisp, SEQ_SPLIT_SOFT, NULL); + SEQ_edit_flag_for_removal(scene, seqbasep, split_strip); + SEQ_edit_remove_flagged_sequences(scene, seqbasep); } /* Trim strips by adjusting handle position. * This is bit more complicated in case overlap happens on effect. */ -static void seq_transform_handle_overwrite_trim(const TransInfo *t, +static void seq_transform_handle_overwrite_trim(Scene *scene, + ListBase *seqbasep, const Sequence *transformed, Sequence *target, const eOvelapDescrition overlap) { - SeqCollection *targets = SEQ_query_by_reference( - target, seqbase_active_get(t), SEQ_query_strip_effect_chain); + SeqCollection *targets = SEQ_query_by_reference(target, seqbasep, SEQ_query_strip_effect_chain); /* Expand collection by adding all target's children, effects and their children. */ if ((target->type & SEQ_TYPE_EFFECT) != 0) { - SEQ_collection_expand(seqbase_active_get(t), targets, SEQ_query_strip_effect_chain); + SEQ_collection_expand(seqbasep, targets, SEQ_query_strip_effect_chain); } /* Trim all non effects, that have influence on effect length which is overlapping. */ @@ -494,15 +496,16 @@ static void seq_transform_handle_overwrite_trim(const TransInfo *t, SEQ_transform_set_right_handle_frame(seq, transformed->startdisp); } - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene)); - SEQ_time_update_sequence(t->scene, seqbase, seq); + SEQ_time_update_sequence(scene, seqbasep, seq); } SEQ_collection_free(targets); } -static void seq_transform_handle_overwrite(const TransInfo *t, SeqCollection *transformed_strips) +static void seq_transform_handle_overwrite(Scene *scene, + ListBase *seqbasep, + SeqCollection *transformed_strips) { - SeqCollection *targets = query_overwrite_targets(t, transformed_strips); + SeqCollection *targets = query_overwrite_targets(seqbasep, transformed_strips); SeqCollection *strips_to_delete = SEQ_collection_create(__func__); Sequence *target; @@ -519,10 +522,10 @@ static void seq_transform_handle_overwrite(const TransInfo *t, SeqCollection *tr SEQ_collection_append_strip(target, strips_to_delete); } else if (overlap == STRIP_OVERLAP_IS_INSIDE) { - seq_transform_handle_overwrite_split(t, transformed, target); + seq_transform_handle_overwrite_split(scene, seqbasep, transformed, target); } else if (ELEM(overlap, STRIP_OVERLAP_LEFT_SIDE, STRIP_OVERLAP_RIGHT_SIDE)) { - seq_transform_handle_overwrite_trim(t, transformed, target, overlap); + seq_transform_handle_overwrite_trim(scene, seqbasep, transformed, target, overlap); } } } @@ -534,47 +537,49 @@ static void seq_transform_handle_overwrite(const TransInfo *t, SeqCollection *tr if (SEQ_collection_len(strips_to_delete) > 0) { Sequence *seq; SEQ_ITERATOR_FOREACH (seq, strips_to_delete) { - SEQ_edit_flag_for_removal(t->scene, seqbase_active_get(t), seq); + SEQ_edit_flag_for_removal(scene, seqbasep, seq); } - SEQ_edit_remove_flagged_sequences(t->scene, seqbase_active_get(t)); + SEQ_edit_remove_flagged_sequences(scene, seqbasep); } SEQ_collection_free(strips_to_delete); } -static void seq_transform_handle_overlap_shuffle(const TransInfo *t, - SeqCollection *transformed_strips) +static void seq_transform_handle_overlap_shuffle(Scene *scene, + ListBase *seqbasep, + SeqCollection *transformed_strips, + bool use_sync_markers) { - ListBase *seqbase = seqbase_active_get(t); - ListBase *markers = &t->scene->markers; - const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag & - SEQ_MARKER_TRANS) != 0; + ListBase *markers = &scene->markers; + /* Shuffle non strips with no effects attached. */ SeqCollection *standalone_strips = extract_standalone_strips(transformed_strips); SEQ_transform_seqbase_shuffle_time( - standalone_strips, seqbase, t->scene, markers, use_sync_markers); + standalone_strips, seqbasep, scene, markers, use_sync_markers); SEQ_collection_free(standalone_strips); } -static void seq_transform_handle_overlap(TransInfo *t, SeqCollection *transformed_strips) +void SEQ_transform_handle_overlap(Scene *scene, + ListBase *seqbasep, + SeqCollection *transformed_strips, + bool use_sync_markers) { - ListBase *seqbasep = seqbase_active_get(t); - const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(t->scene); + const eSeqOverlapMode overlap_mode = SEQ_tool_settings_overlap_mode_get(scene); switch (overlap_mode) { case SEQ_OVERLAP_EXPAND: - seq_transform_handle_expand_to_fit(t, transformed_strips); + seq_transform_handle_expand_to_fit(scene, seqbasep, transformed_strips, use_sync_markers); break; case SEQ_OVERLAP_OVERWRITE: - seq_transform_handle_overwrite(t, transformed_strips); + seq_transform_handle_overwrite(scene, seqbasep, transformed_strips); break; case SEQ_OVERLAP_SHUFFLE: - seq_transform_handle_overlap_shuffle(t, transformed_strips); + seq_transform_handle_overlap_shuffle(scene, seqbasep, transformed_strips, use_sync_markers); break; } if (seq_transform_check_strip_effects(transformed_strips)) { /* Update effect strips based on strips just moved in time. */ - seq_transform_update_effects(t, transformed_strips); + seq_transform_update_effects(scene, seqbasep, transformed_strips); } /* If any effects still overlap, we need to move them up. @@ -582,7 +587,7 @@ static void seq_transform_handle_overlap(TransInfo *t, SeqCollection *transforme Sequence *seq; SEQ_ITERATOR_FOREACH (seq, transformed_strips) { if (SEQ_transform_test_overlap(seqbasep, seq)) { - SEQ_transform_seqbase_shuffle(seqbasep, seq, t->scene); + SEQ_transform_seqbase_shuffle(seqbasep, seq, scene); } seq->flag &= ~SEQ_OVERLAP; } @@ -622,11 +627,15 @@ static void freeSeqData(TransInfo *t, TransDataContainer *tc, TransCustomData *c return; } + ListBase *seqbasep = seqbase_active_get(t); + Scene *scene = t->scene; + const bool use_sync_markers = (((SpaceSeq *)t->area->spacedata.first)->flag & + SEQ_MARKER_TRANS) != 0; if (seq_transform_check_overlap(transformed_strips)) { - seq_transform_handle_overlap(t, transformed_strips); + SEQ_transform_handle_overlap(scene, seqbasep, transformed_strips, use_sync_markers); } - seq_transform_update_effects(t, transformed_strips); + seq_transform_update_effects(scene, seqbasep, transformed_strips); SEQ_collection_free(transformed_strips); SEQ_sort(ed->seqbasep); diff --git a/source/blender/editors/transform/transform_orientations.h b/source/blender/editors/transform/transform_orientations.h index 5bca05b0c3a..3ac235517a7 100644 --- a/source/blender/editors/transform/transform_orientations.h +++ b/source/blender/editors/transform/transform_orientations.h @@ -7,6 +7,8 @@ #pragma once +#include "RE_engine.h" + struct TransInfo; /** diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c index 7715388bf52..7dc361ff5bb 100644 --- a/source/blender/editors/transform/transform_snap_sequencer.c +++ b/source/blender/editors/transform/transform_snap_sequencer.c @@ -15,6 +15,7 @@ #include "BKE_context.h" #include "ED_screen.h" +#include "ED_transform.h" #include "UI_view2d.h" @@ -33,7 +34,6 @@ typedef struct TransSeqSnapData { int *target_snap_points; int source_snap_point_count; int target_snap_point_count; - int final_snap_frame; } TransSeqSnapData; /* -------------------------------------------------------------------- */ @@ -58,9 +58,7 @@ static int cmp_fn(const void *a, const void *b) return (*(int *)a - *(int *)b); } -static void seq_snap_source_points_build(const TransInfo *UNUSED(t), - TransSeqSnapData *snap_data, - SeqCollection *snap_sources) +static void seq_snap_source_points_build(TransSeqSnapData *snap_data, SeqCollection *snap_sources) { int i = 0; Sequence *seq; @@ -121,15 +119,17 @@ static SeqCollection *seq_collection_extract_effects(SeqCollection *collection) return effects; } -static SeqCollection *query_snap_targets(const TransInfo *t, SeqCollection *snap_sources) +static SeqCollection *query_snap_targets(Scene *scene, + SeqCollection *snap_sources, + bool exclude_selected) { - Editing *ed = SEQ_editing_get(t->scene); + Editing *ed = SEQ_editing_get(scene); ListBase *seqbase = SEQ_active_seqbase_get(ed); ListBase *channels = SEQ_channels_displayed_get(ed); - const short snap_flag = SEQ_tool_settings_snap_flag_get(t->scene); + const short snap_flag = SEQ_tool_settings_snap_flag_get(scene); SeqCollection *snap_targets = SEQ_collection_create(__func__); LISTBASE_FOREACH (Sequence *, seq, seqbase) { - if (seq->flag & SELECT) { + if (exclude_selected && seq->flag & SELECT) { continue; /* Selected are being transformed. */ } if (SEQ_render_is_muted(channels, seq) && (snap_flag & SEQ_SNAP_IGNORE_MUTED)) { @@ -152,12 +152,8 @@ static SeqCollection *query_snap_targets(const TransInfo *t, SeqCollection *snap return snap_targets; } -static int seq_get_snap_target_points_count(const TransInfo *t, - TransSeqSnapData *UNUSED(snap_data), - SeqCollection *snap_targets) +static int seq_get_snap_target_points_count(short snap_mode, SeqCollection *snap_targets) { - const short snap_mode = t->tsnap.mode; - int count = 2; /* Strip start and end are always used. */ if (snap_mode & SEQ_SNAP_TO_STRIP_HOLD) { @@ -173,23 +169,21 @@ static int seq_get_snap_target_points_count(const TransInfo *t, return count; } -static void seq_snap_target_points_alloc(const TransInfo *t, +static void seq_snap_target_points_alloc(short snap_mode, TransSeqSnapData *snap_data, SeqCollection *snap_targets) { - const size_t point_count = seq_get_snap_target_points_count(t, snap_data, snap_targets); + const size_t point_count = seq_get_snap_target_points_count(snap_mode, snap_targets); snap_data->target_snap_points = MEM_callocN(sizeof(int) * point_count, __func__); memset(snap_data->target_snap_points, 0, sizeof(int)); snap_data->target_snap_point_count = point_count; } -static void seq_snap_target_points_build(const TransInfo *t, +static void seq_snap_target_points_build(Scene *scene, + short snap_mode, TransSeqSnapData *snap_data, SeqCollection *snap_targets) { - const Scene *scene = t->scene; - const short snap_mode = t->tsnap.mode; - int i = 0; if (snap_mode & SEQ_SNAP_TO_CURRENT_FRAME) { @@ -246,11 +240,12 @@ TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t) return NULL; } + Scene *scene = t->scene; TransSeqSnapData *snap_data = MEM_callocN(sizeof(TransSeqSnapData), __func__); - ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(t->scene)); + ListBase *seqbase = SEQ_active_seqbase_get(SEQ_editing_get(scene)); SeqCollection *snap_sources = SEQ_query_selected_strips(seqbase); - SeqCollection *snap_targets = query_snap_targets(t, snap_sources); + SeqCollection *snap_targets = query_snap_targets(scene, snap_sources, true); if (SEQ_collection_len(snap_sources) == 0) { SEQ_collection_free(snap_targets); @@ -261,11 +256,12 @@ TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t) /* Build arrays of snap points. */ seq_snap_source_points_alloc(snap_data, snap_sources); - seq_snap_source_points_build(t, snap_data, snap_sources); + seq_snap_source_points_build(snap_data, snap_sources); SEQ_collection_free(snap_sources); - seq_snap_target_points_alloc(t, snap_data, snap_targets); - seq_snap_target_points_build(t, snap_data, snap_targets); + short snap_mode = t->tsnap.mode; + seq_snap_target_points_alloc(snap_mode, snap_data, snap_targets); + seq_snap_target_points_build(scene, snap_mode, snap_data, snap_targets); SEQ_collection_free(snap_targets); return snap_data; @@ -321,3 +317,73 @@ void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec) { *vec += t->tsnap.snapPoint[0] - t->tsnap.snapTarget[0]; } + +static int transform_snap_sequencer_to_closest_strip_ex(TransInfo *t, int frame_1, int frame_2) +{ + Scene *scene = t->scene; + TransSeqSnapData *snap_data = MEM_callocN(sizeof(TransSeqSnapData), __func__); + + SeqCollection *empty_col = SEQ_collection_create(__func__); + SeqCollection *snap_targets = query_snap_targets(scene, empty_col, false); + SEQ_collection_free(empty_col); + + snap_data->source_snap_points = MEM_callocN(sizeof(int) * 2, __func__); + snap_data->source_snap_point_count = 2; + BLI_assert(frame_1 <= frame_2); + snap_data->source_snap_points[0] = frame_1; + snap_data->source_snap_points[1] = frame_2; + + short snap_mode = t->tsnap.mode; + /* Build arrays of snap points. */ + seq_snap_target_points_alloc(snap_mode, snap_data, snap_targets); + seq_snap_target_points_build(scene, snap_mode, snap_data, snap_targets); + SEQ_collection_free(snap_targets); + + t->tsnap.seq_context = snap_data; + bool snap_success = transform_snap_sequencer_calc(t); + transform_snap_sequencer_data_free(snap_data); + t->tsnap.seq_context = NULL; + + float snap_offset = 0; + if (snap_success) { + t->tsnap.status |= (POINT_INIT | TARGET_INIT); + transform_snap_sequencer_apply_translate(t, &snap_offset); + } + else { + t->tsnap.status &= ~(POINT_INIT | TARGET_INIT); + } + + return snap_offset; +} + +bool ED_transform_snap_sequencer_to_closest_strip_calc(Scene *scene, + ARegion *region, + int frame_1, + int frame_2, + int *r_snap_distance, + float *r_snap_frame) +{ + TransInfo t; + t.scene = scene; + t.region = region; + t.values[0] = 0; + t.data_type = TC_SEQ_DATA; + + t.tsnap.mode = SEQ_tool_settings_snap_mode_get(scene); + *r_snap_distance = transform_snap_sequencer_to_closest_strip_ex(&t, frame_1, frame_2); + *r_snap_frame = t.tsnap.snapPoint[0]; + return validSnap(&t); +} + +void ED_draw_sequencer_snap_point(struct bContext *C, float snap_point) +{ + /* Reuse the snapping drawing code from the transform system. */ + TransInfo t; + t.mode = TFM_SEQ_SLIDE; + t.modifiers = MOD_SNAP; + t.spacetype = SPACE_SEQ; + t.tsnap.status = (POINT_INIT | TARGET_INIT); + t.tsnap.snapPoint[0] = snap_point; + + drawSnapping(C, &t); +} diff --git a/source/blender/sequencer/SEQ_transform.h b/source/blender/sequencer/SEQ_transform.h index a342dfe10a2..ea90a3ed372 100644 --- a/source/blender/sequencer/SEQ_transform.h +++ b/source/blender/sequencer/SEQ_transform.h @@ -51,6 +51,11 @@ bool SEQ_transform_seqbase_shuffle_time(struct SeqCollection *strips_to_shuffle, struct Scene *evil_scene, struct ListBase *markers, bool use_sync_markers); + +void SEQ_transform_handle_overlap(struct Scene *scene, + struct ListBase *seqbasep, + struct SeqCollection *transformed_strips, + bool use_sync_markers); /** * Check if the selected seq's reference unselected seq's. */ diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 1427200b9cd..9a4d024328a 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -1164,7 +1164,7 @@ struct wmDropBox *WM_dropbox_add( ListBase *lb, const char *idname, bool (*poll)(struct bContext *, struct wmDrag *, const struct wmEvent *event), - void (*copy)(struct wmDrag *, struct wmDropBox *), + void (*copy)(struct bContext *, struct wmDrag *, struct wmDropBox *), void (*cancel)(struct Main *, struct wmDrag *, struct wmDropBox *), WMDropboxTooltipFunc tooltip); void WM_drag_draw_item_name_fn(struct bContext *C, @@ -1294,6 +1294,7 @@ enum { WM_JOB_TYPE_TRACE_IMAGE, WM_JOB_TYPE_LINEART, WM_JOB_TYPE_SEQ_DRAW_THUMBNAIL, + WM_JOB_TYPE_SEQ_DRAG_DROP_PREVIEW, /* add as needed, bake, seq proxy build * if having hard coded values is a problem */ }; diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 11603b9e5f7..a9b8d91ca03 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -1169,8 +1169,13 @@ typedef struct wmDropBox { /** Test if the dropbox is active. */ bool (*poll)(struct bContext *C, struct wmDrag *drag, const wmEvent *event); + /** Called when the drag action starts. Can be used to prefetch data for previews. + * \note The dropbox that will be called eventually is not known yet when starting the drag. + * So this callback is called on every dropbox that is registered in the current screen. */ + void (*on_drag_start)(struct bContext *C, struct wmDrag *drag); + /** Before exec, this copies drag info to #wmDrop properties. */ - void (*copy)(struct wmDrag *drag, struct wmDropBox *drop); + void (*copy)(struct bContext *C, struct wmDrag *drag, struct wmDropBox *drop); /** * If the operator is canceled (returns `OPERATOR_CANCELLED`), this can be used for cleanup of @@ -1179,15 +1184,29 @@ typedef struct wmDropBox { void (*cancel)(struct Main *bmain, struct wmDrag *drag, struct wmDropBox *drop); /** - * Override the default drawing function. + * Override the default cursor overlay drawing function. + * Can be used to draw text or thumbnails. IE a tooltip for drag and drop. + * \param xy: Cursor location in window coordinates (#wmEvent.xy compatible). + */ + void (*draw_droptip)(struct bContext *C, + struct wmWindow *win, + struct wmDrag *drag, + const int xy[2]); + + /** Called with the draw buffer (#GPUViewport) set up for drawing into the region's view. + * \note Only setups the drawing buffer for drawing in view, not the GPU transform matricies. + * The callback has to do that itself, with for example #UI_view2d_view_ortho. * \param xy: Cursor location in window coordinates (#wmEvent.xy compatible). */ - void (*draw)(struct bContext *C, struct wmWindow *win, struct wmDrag *drag, const int xy[2]); + void (*draw_in_view)(struct bContext *C, + struct wmWindow *win, + struct wmDrag *drag, + const int xy[2]); - /** Called when pool returns true the first time. */ + /** Called when poll returns true the first time. */ void (*draw_activate)(struct wmDropBox *drop, struct wmDrag *drag); - /** Called when pool returns false the first time or when the drag event ends. */ + /** Called when poll returns false the first time or when the drag event ends. */ void (*draw_deactivate)(struct wmDropBox *drop, struct wmDrag *drag); /** Custom data for drawing. */ diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 4970b09c18b..a98ded82a92 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -17,6 +17,7 @@ #include "BLT_translation.h" +#include "BLI_bitmap.h" #include "BLI_blenlib.h" #include "BLI_math_color.h" @@ -95,7 +96,7 @@ ListBase *WM_dropboxmap_find(const char *idname, int spaceid, int regionid) wmDropBox *WM_dropbox_add(ListBase *lb, const char *idname, bool (*poll)(bContext *, wmDrag *, const wmEvent *), - void (*copy)(wmDrag *, wmDropBox *), + void (*copy)(bContext *, wmDrag *, wmDropBox *), void (*cancel)(struct Main *, wmDrag *, wmDropBox *), WMDropboxTooltipFunc tooltip) { @@ -136,6 +137,44 @@ void wm_dropbox_free(void) /* *********************************** */ +static void wm_dropbox_invoke(bContext *C, wmDrag *drag) +{ + wmWindowManager *wm = CTX_wm_manager(C); + + /* Create a bitmap flag matrix of all currently visible region and area types. + * Everything that isn't visible in the current window should not prefetch any data. */ + bool area_region_tag[SPACE_TYPE_NUM][RGN_TYPE_NUM] = {{false}}; + + LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { + bScreen *screen = WM_window_get_active_screen(win); + ED_screen_areas_iter (win, screen, area) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { + if (region->visible) { + BLI_assert(area->spacetype < SPACE_TYPE_NUM); + BLI_assert(region->regiontype < RGN_TYPE_NUM); + area_region_tag[area->spacetype][region->regiontype] = true; + } + } + } + } + + LISTBASE_FOREACH (wmDropBoxMap *, dm, &dropboxes) { + if (!area_region_tag[dm->spaceid][dm->regionid]) { + continue; + } + LISTBASE_FOREACH (wmDropBox *, drop, &dm->dropboxes) { + if (drag->drop_state.ui_context) { + CTX_store_set(C, drag->drop_state.ui_context); + } + + if (drop->on_drag_start) { + drop->on_drag_start(C, drag); + } + CTX_store_set(C, NULL); + } + } +} + wmDrag *WM_event_start_drag( struct bContext *C, int icon, int type, void *poin, double value, unsigned int flags) { @@ -187,6 +226,8 @@ wmDrag *WM_event_start_drag( } drag->value = value; + wm_dropbox_invoke(C, drag); + return drag; } @@ -416,7 +457,7 @@ void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop) * operator fails anyway, it might do more than just set properties (e.g. * typically import an asset). */ if (drop->copy && WM_operator_poll_context(C, drop->ot, opcontext)) { - drop->copy(drag, drop); + drop->copy(C, drag, drop); } wm_drags_exit(CTX_wm_manager(C), CTX_wm_window(C)); @@ -947,10 +988,16 @@ void wm_drags_draw(bContext *C, wmWindow *win) CTX_wm_region_set(C, drag->drop_state.region_from); CTX_store_set(C, drag->drop_state.ui_context); + if (region && drag->drop_state.active_dropbox->draw_in_view) { + wmViewport(®ion->winrct); + drag->drop_state.active_dropbox->draw_in_view(C, win, drag, xy); + wmWindowViewport(win); + } + /* Drawing should be allowed to assume the context from handling and polling (that's why we * restore it above). */ - if (drag->drop_state.active_dropbox->draw) { - drag->drop_state.active_dropbox->draw(C, win, drag, xy); + if (drag->drop_state.active_dropbox->draw_droptip) { + drag->drop_state.active_dropbox->draw_droptip(C, win, drag, xy); continue; } } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 4b506564260..242c96903d3 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -863,6 +863,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) /* Needs pixel coords in screen. */ if (wm->drags.first) { wm_drags_draw(C, win); + wmWindowViewport(win); } GPU_debug_group_end(); |