IO: Use file handler in space VSE #119927

Merged
Richard Antalik merged 7 commits from guishe/blender:video-seq-fh into main 2024-05-06 17:45:02 +02:00
3 changed files with 107 additions and 14 deletions

View File

@ -3,7 +3,10 @@
# SPDX-License-Identifier: GPL-2.0-or-later
import bpy
from bpy.types import Operator
from bpy.types import (
FileHandler,
Operator,
)
from bpy.props import (
EnumProperty,
@ -373,10 +376,46 @@ def calculate_duration_frames(scene, duration_seconds):
return round(duration_seconds * scene.render.fps / scene.render.fps_base)
class SequencerFileHandlerBase:
@classmethod
def poll_drop(cls, context):
return (
(context.region is not None) and
(context.region.type == 'WINDOW') and
(context.area is not None) and
(context.area.ui_type == 'SEQUENCE_EDITOR')
)
class SEQUENCER_FH_image_strip(FileHandler, SequencerFileHandlerBase):
bl_idname = "SEQUENCER_FH_image_strip"
bl_label = "Image strip"
bl_import_operator = "SEQUENCER_OT_image_strip_add"
bl_file_extensions = ";".join(bpy.path.extensions_image)
class SEQUENCER_FH_movie_strip(FileHandler, SequencerFileHandlerBase):
bl_idname = "SEQUENCER_FH_movie_strip"
bl_label = "Movie strip"
bl_import_operator = "SEQUENCER_OT_movie_strip_add"
bl_file_extensions = ";".join(bpy.path.extensions_movie)
class SEQUENCER_FH_sound_strip(FileHandler, SequencerFileHandlerBase):
bl_idname = "SEQUENCER_FH_sound_strip"
bl_label = "Sound strip"
bl_import_operator = "SEQUENCER_OT_sound_strip_add"
bl_file_extensions = ";".join(bpy.path.extensions_audio)
classes = (
SequencerCrossfadeSounds,
SequencerSplitMulticam,
SequencerDeinterlaceSelectedMovies,
SequencerFadesClear,
SequencerFadesAdd,
SEQUENCER_FH_image_strip,
SEQUENCER_FH_movie_strip,
SEQUENCER_FH_sound_strip,
)

View File

@ -50,6 +50,7 @@
#include "ED_sequencer.hh"
#include "UI_interface.hh"
#include "UI_view2d.hh"
#ifdef WITH_AUDASPACE
# include <AUD_Sequence.h>
@ -203,11 +204,42 @@ static int sequencer_generic_invoke_xy_guess_channel(bContext *C, int type)
return 1;
}
static void sequencer_generic_invoke_xy__internal(bContext *C, wmOperator *op, int flag, int type)
/* Sets `channel` and `frame_start` properties when the operator is likely to have been invoked
* with drag-and-drop data. */
static void sequencer_file_drop_channel_frame_set(bContext *C,
wmOperator *op,
const wmEvent *event)
{
BLI_assert((RNA_struct_property_is_set(op->ptr, "files") &&
!RNA_collection_is_empty(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath"));
if (RNA_struct_property_is_set(op->ptr, "channel") ||
RNA_struct_property_is_set(op->ptr, "frame_start"))
{
return;
}
ARegion *region = CTX_wm_region(C);
if (!region || region->regiontype != RGN_TYPE_WINDOW) {
return;
}
float frame_start, channel;
UI_view2d_region_to_view(&region->v2d, event->mval[0], event->mval[1], &frame_start, &channel);
RNA_int_set(op->ptr, "channel", int(channel));
RNA_int_set(op->ptr, "frame_start", int(frame_start));
}
static void sequencer_generic_invoke_xy__internal(
bContext *C, wmOperator *op, int flag, int type, const wmEvent *event = nullptr)
{
Scene *scene = CTX_data_scene(C);
int timeline_frame = int(scene->r.cfra);
if ((flag & SEQPROP_NOPATHS) && event) {
sequencer_file_drop_channel_frame_set(C, op, event);
}
/* Effect strips don't need a channel initialized from the mouse. */
if (!(flag & SEQPROP_NOCHAN) && RNA_struct_property_is_set(op->ptr, "channel") == 0) {
@ -964,7 +996,7 @@ static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
PropertyRNA *prop;
Scene *scene = CTX_data_scene(C);
@ -979,7 +1011,7 @@ static int sequencer_add_movie_strip_invoke(bContext *C, wmOperator *op, const w
!RNA_collection_is_empty(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath"))
{
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_MOVIE);
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_MOVIE, event);
return sequencer_add_movie_strip_exec(C, op);
}
@ -1132,14 +1164,14 @@ static int sequencer_add_sound_strip_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
static int sequencer_add_sound_strip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
/* This is for drag and drop. */
if ((RNA_struct_property_is_set(op->ptr, "files") &&
!RNA_collection_is_empty(op->ptr, "files")) ||
RNA_struct_property_is_set(op->ptr, "filepath"))
{
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_SOUND_RAM);
sequencer_generic_invoke_xy__internal(C, op, SEQPROP_NOPATHS, SEQ_TYPE_SOUND_RAM, event);
return sequencer_add_sound_strip_exec(C, op);
}
@ -1320,7 +1352,7 @@ static int sequencer_add_image_strip_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
PropertyRNA *prop;
Scene *scene = CTX_data_scene(C);
@ -1332,7 +1364,7 @@ static int sequencer_add_image_strip_invoke(bContext *C, wmOperator *op, const w
/* Name set already by drag and drop. */
if (RNA_struct_property_is_set(op->ptr, "files") && !RNA_collection_is_empty(op->ptr, "files")) {
sequencer_generic_invoke_xy__internal(
C, op, SEQPROP_ENDFRAME | SEQPROP_NOPATHS, SEQ_TYPE_IMAGE);
C, op, SEQPROP_ENDFRAME | SEQPROP_NOPATHS, SEQ_TYPE_IMAGE, event);
return sequencer_add_image_strip_exec(C, op);
}

View File

@ -12,9 +12,11 @@
#include "DNA_sound_types.h"
#include "BLI_blenlib.h"
#include "BLI_string_ref.hh"
#include "BLI_string_utils.hh"
#include "BKE_context.hh"
#include "BKE_file_handler.hh"
#include "BKE_image.h"
#include "BKE_main.hh"
@ -75,11 +77,27 @@ static void generic_poll_operations(const wmEvent *event, uint8_t type)
g_drop_coords.use_snapping = event->modifier & KM_CTRL;
}
static bool image_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent *event)
/* While drag-and-drop in the sequencer, the internal drop-box implementation allows to have a drop
* preview of the file dragged. This checks when drag-and-drop is done with a single file, and when
* only a expected `file_handler` can be used, so internal drop-box can be used instead of the
* `file_handler`. */
static bool test_single_file_handler_poll(const bContext *C,
Review

Not sure if I am following this well - is internal drop-box the system, VSE was usin previously? If so, is the purpose of this function allow for strip placement visualization by drawing it? And in such case would it be technically possible to do such visualization with multiple strips?

So Ultimately I am thinking that we use 2 systems I guess, and ideally we would use only 1. But perhaps I am not getting this right.

Not sure if I am following this well - is internal drop-box the system, VSE was usin previously? If so, is the purpose of this function allow for strip placement visualization by drawing it? And in such case would it be technically possible to do such visualization with multiple strips? So Ultimately I am thinking that we use 2 systems I guess, and ideally we would use only 1. But perhaps I am not getting this right.

And in such case would it be technically possible to do such visualization with multiple strips?

Currently not, preview can be done with blender internal file browser drag-and-drop, but internal file browser currently only support single file drag (there is a patch to add multiple file drag support)
External file browser drag-and-drop support multiple files but currently only the drop event is registered to blender.

So Ultimately I am thinking that we use 2 systems I guess, and ideally we would use only 1

Ideally yes, the FileHandler is the api that allows file drag-and-drop support to addons too, but currently its lack a way to generate such preview, so the internal drag-and-drop system is used too to keep the this preview (only when no other FileHandler can be used).

This is mostly to allow addons to be registered for drag-and-drop in VSE with this same files types, but top keep the preview if the user has no installed a add-on that can.

>And in such case would it be technically possible to do such visualization with multiple strips? Currently not, preview can be done with blender internal file browser drag-and-drop, but internal file browser currently only support single file drag (there is a patch to add multiple file drag support) External file browser drag-and-drop support multiple files but currently only the drop event is registered to blender. >So Ultimately I am thinking that we use 2 systems I guess, and ideally we would use only 1 Ideally yes, the `FileHandler` is the api that allows file drag-and-drop support to addons too, but currently its lack a way to generate such preview, so the internal drag-and-drop system is used too to keep the this preview (only when no other `FileHandler` can be used). This is mostly to allow addons to be registered for drag-and-drop in VSE with this same files types, but top keep the preview if the user has no installed a add-on that can.

@brecht I wanted to see if you have an opinion on this too

@brecht I wanted to see if you have an opinion on this too
wmDrag *drag,
blender::StringRef file_handler)
{
const auto paths = WM_drag_get_paths(drag);
auto file_handlers = blender::bke::file_handlers_poll_file_drop(C, paths);
return paths.size() == 1 && file_handlers.size() == 1 &&
file_handler == file_handlers[0]->idname;
}
static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
if (drag->type == WM_DRAG_PATH) {
const eFileSel_File_Types file_type = eFileSel_File_Types(WM_drag_get_path_file_type(drag));
if (file_type == FILE_TYPE_IMAGE) {
if (file_type == FILE_TYPE_IMAGE &&
test_single_file_handler_poll(C, drag, "SEQUENCER_FH_image_strip"))
{
generic_poll_operations(event, TH_SEQ_IMAGE);
return true;
}
@ -107,9 +125,11 @@ static bool is_movie(wmDrag *drag)
return false;
}
static bool movie_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent *event)
static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
if (is_movie(drag)) {
if (is_movie(drag) && (drag->type != WM_DRAG_PATH ||
test_single_file_handler_poll(C, drag, "SEQUENCER_FH_movie_strip")))
{
generic_poll_operations(event, TH_SEQ_MOVIE);
return true;
}
@ -131,9 +151,11 @@ static bool is_sound(wmDrag *drag)
return false;
}
static bool sound_drop_poll(bContext * /*C*/, wmDrag *drag, const wmEvent *event)
static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
{
if (is_sound(drag)) {
if (is_sound(drag) && (drag->type != WM_DRAG_PATH ||
test_single_file_handler_poll(C, drag, "SEQUENCER_FH_sound_strip")))
{
generic_poll_operations(event, TH_SEQ_AUDIO);
return true;
}