VSE: Add precise drag and drop and strip previews

This patch adds the drag and drop strip previews in the VSE.
It also adds two new functions to the drag and drop API.

1. "draw_in_view" for callbacks that wants to draw elements in local viewport coordinates
2. "on_drag_start" that can be used for prefetching data only once at the start of the drag.

Reviewed By: Julian, Campbell

Differential Revision: http://developer.blender.org/D14560
This commit is contained in:
Sebastian Parborg 2022-04-28 12:50:22 +02:00
parent 16fe767d00
commit 77794b1a7b
Notes: blender-bot 2023-02-14 06:17:14 +01:00
Referenced by issue #100300, Regression: Dropping a file in VSE does not create the strip at the cursor position as it did before
Referenced by issue #99266, Regression: Blender Crashes when adding new video to new scene in VSE
Referenced by issue #99255, VSE movie clips inserting incorrectly
27 changed files with 1062 additions and 259 deletions

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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];

View File

@ -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);

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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

View File

@ -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,11 +323,51 @@ 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),
@ -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;

View File

@ -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 = &region->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, &region->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(&region->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(&region->v2d.cur) / BLI_rcti_size_x(&region->v2d.mask);
float pixely = BLI_rctf_size_y(&region->v2d.cur) / BLI_rcti_size_y(&region->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(
&region->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);
}

View File

@ -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);

View File

@ -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, &region->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, &region->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, &region->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};

View File

@ -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);

View File

@ -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;

View File

@ -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"

View File

@ -8,6 +8,8 @@
#pragma once
#include "RE_engine.h"
struct BMEditMesh;
struct BMesh;
struct BezTriple;

View File

@ -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);

View File

@ -7,6 +7,8 @@
#pragma once
#include "RE_engine.h"
struct TransInfo;
/**

View File

@ -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);
}

View File

@ -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.
*/

View File

@ -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 */
};

View File

@ -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)(struct bContext *C, struct wmWindow *win, struct wmDrag *drag, const int xy[2]);
void (*draw_droptip)(struct bContext *C,
struct wmWindow *win,
struct wmDrag *drag,
const int xy[2]);
/** Called when pool returns true the first time. */
/** 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_in_view)(struct bContext *C,
struct wmWindow *win,
struct wmDrag *drag,
const int xy[2]);
/** 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. */

View File

@ -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(&region->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;
}
}

View File

@ -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();