mirror of
https://github.com/blender/blender
synced 2026-09-29 04:37:17 +03:00
VSE: Add drag-and-drop support for text datablocks and text files
Note that to support "multiple text files dragged in at once" we need to use file handlers, which can't be passed any custom data (e.g. can't set "text" property before calling SEQUENCER_OT_effect_strip_add). To get around this I just added a new SEQUENCER_OT_text_strip_add rather than try to change any file handler code. This should be backwards compatible; scripts can continue to call effect_strip_add. But we might want to move to the new operator for 6.0 (see #154702). Ref: !163440
This commit is contained in:
parent
5ae3e6f918
commit
ea1680d241
6 changed files with 237 additions and 3 deletions
|
|
@ -421,6 +421,13 @@ class SEQUENCER_FH_sound_strip(FileHandler, SequencerFileHandlerBase):
|
|||
bl_file_extensions = ";".join(bpy.path.extensions_audio)
|
||||
|
||||
|
||||
class SEQUENCER_FH_text_strip(FileHandler, SequencerFileHandlerBase):
|
||||
bl_idname = "SEQUENCER_FH_text_strip"
|
||||
bl_label = "Text strip"
|
||||
bl_import_operator = "SEQUENCER_OT_text_strip_add"
|
||||
bl_file_extensions = ".txt"
|
||||
|
||||
|
||||
classes = (
|
||||
SequencerCrossfadeSounds,
|
||||
SequencerSplitMulticam,
|
||||
|
|
@ -431,4 +438,5 @@ classes = (
|
|||
SEQUENCER_FH_image_strip,
|
||||
SEQUENCER_FH_movie_strip,
|
||||
SEQUENCER_FH_sound_strip,
|
||||
SEQUENCER_FH_text_strip,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -720,7 +720,7 @@ class SEQUENCER_MT_add(Menu):
|
|||
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
layout.operator("sequencer.effect_strip_add", text="Color", icon='COLOR').type = 'COLOR'
|
||||
layout.operator("sequencer.effect_strip_add", text="Text", icon='FONT_DATA').type = 'TEXT'
|
||||
layout.operator("sequencer.text_strip_add", text="Text", icon='FONT_DATA')
|
||||
|
||||
layout.separator()
|
||||
total, nonsound = selected_strips_count(context)
|
||||
|
|
|
|||
|
|
@ -16,10 +16,12 @@
|
|||
#include "DNA_sound_types.h"
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_fileops.hh"
|
||||
#include "BLI_listbase.hh"
|
||||
#include "BLI_math_base_c.hh"
|
||||
#include "BLI_path_utils.hh"
|
||||
#include "BLI_string.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_string_utf8.hh"
|
||||
#include "BLI_utildefines.hh"
|
||||
|
||||
|
|
@ -1949,6 +1951,161 @@ void SEQUENCER_OT_image_strip_add(wmOperatorType *ot)
|
|||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Add Text Strip
|
||||
* \{ */
|
||||
|
||||
static Strip *sequencer_add_text_strip(bContext *C,
|
||||
wmOperator *op,
|
||||
seq::LoadData *load_data,
|
||||
const StringRef text)
|
||||
{
|
||||
Scene *scene = CTX_data_sequencer_scene(C);
|
||||
Editing *ed = seq::editing_ensure(scene);
|
||||
|
||||
load_data->effect.type = STRIP_TYPE_TEXT;
|
||||
Strip *strip = seq::add_effect_strip(scene, ed->current_strips(), load_data);
|
||||
seq_load_apply_generic_options(C, op, strip);
|
||||
|
||||
TextVars *textvars = static_cast<TextVars *>(strip->effectdata);
|
||||
if (!text.is_empty()) {
|
||||
/* Make sure to delete default text ("Text") before overriding it. */
|
||||
MEM_SAFE_DELETE(textvars->text_ptr);
|
||||
textvars->text_ptr = BLI_strdupn(text.data(), text.size());
|
||||
textvars->text_len_bytes = text.size();
|
||||
textvars->cursor_offset = BLI_strlen_utf8(textvars->text_ptr);
|
||||
}
|
||||
textvars->runtime = MEM_new<seq::TextVarsRuntime>(__func__);
|
||||
seq::text_effect_update_runtime(nullptr, *textvars, int2(scene->r.xsch, scene->r.ysch));
|
||||
|
||||
return strip;
|
||||
}
|
||||
|
||||
static Strip *sequencer_add_text_strip_from_file(bContext *C,
|
||||
wmOperator *op,
|
||||
seq::LoadData *load_data)
|
||||
{
|
||||
size_t buf_len;
|
||||
char *buf = BLI_file_read_text_as_mem(load_data->path, 1, &buf_len);
|
||||
if (buf == nullptr) {
|
||||
BKE_reportf(op->reports, RPT_ERROR, "File '%s' could not be loaded", load_data->path);
|
||||
return nullptr;
|
||||
}
|
||||
buf[buf_len] = '\0';
|
||||
|
||||
Strip *strip = sequencer_add_text_strip(C, op, load_data, StringRef(buf, buf_len));
|
||||
MEM_delete(buf);
|
||||
|
||||
return strip;
|
||||
}
|
||||
|
||||
static wmOperatorStatus sequencer_add_text_strip_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
if ((op->flag & OP_IS_INVOKE) && !WM_operator_poll_or_report_error(C, op->type, op->reports)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
Scene *scene = CTX_data_sequencer_scene(C);
|
||||
|
||||
seq::LoadData load_data;
|
||||
if (!sequencer_add_generic_exec(C, op, &load_data, scene, 1)) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (RNA_collection_is_empty(op->ptr, "files")) {
|
||||
sequencer_add_text_strip(C, op, &load_data, RNA_string_get(op->ptr, "text"));
|
||||
}
|
||||
else {
|
||||
char directory[FILE_MAX];
|
||||
RNA_string_get(op->ptr, "directory", directory);
|
||||
|
||||
RNA_BEGIN (op->ptr, itemptr, "files") {
|
||||
char filename[FILE_MAX];
|
||||
RNA_string_get(&itemptr, "name", filename);
|
||||
BLI_path_join(load_data.path, sizeof(load_data.path), directory, filename);
|
||||
STRNCPY(load_data.name, filename);
|
||||
|
||||
const Strip *strip = sequencer_add_text_strip_from_file(C, op, &load_data);
|
||||
if (strip != nullptr) {
|
||||
load_data.start_frame += strip->right_handle(scene) - strip->left_handle();
|
||||
}
|
||||
}
|
||||
RNA_END;
|
||||
}
|
||||
|
||||
DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
|
||||
sequencer_select_do_updates(C, scene);
|
||||
move_strips(C, op);
|
||||
|
||||
sequencer_add_free(C, op);
|
||||
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
static wmOperatorStatus sequencer_add_text_strip_invoke(bContext *C,
|
||||
wmOperator *op,
|
||||
const wmEvent *event)
|
||||
{
|
||||
sequencer_add_init(C, op);
|
||||
|
||||
const wmEvent *drop_event = is_drag_and_drop(op, event) ? event : nullptr;
|
||||
sequencer_generic_invoke_xy__internal(
|
||||
C, op, SEQPROP_LENGTH | SEQPROP_NOPATHS, STRIP_TYPE_TEXT, drop_event);
|
||||
|
||||
return sequencer_add_text_strip_exec(C, op);
|
||||
}
|
||||
|
||||
static bool sequencer_add_text_strip_poll_property(const bContext * /*C*/,
|
||||
wmOperator *op,
|
||||
const PropertyRNA *prop)
|
||||
{
|
||||
const char *prop_id = RNA_property_identifier(prop);
|
||||
|
||||
if (STR_ELEM(prop_id, "filepath", "directory", "filename", "relative_path")) {
|
||||
return !RNA_collection_is_empty(op->ptr, "files");
|
||||
}
|
||||
if (STREQ(prop_id, "text")) {
|
||||
return RNA_collection_is_empty(op->ptr, "files");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SEQUENCER_OT_text_strip_add(wmOperatorType *ot)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
/* Identifiers. */
|
||||
ot->name = "Add Text Strip";
|
||||
ot->idname = "SEQUENCER_OT_text_strip_add";
|
||||
ot->description = "Add a text strip to the sequencer";
|
||||
|
||||
/* API callbacks. */
|
||||
ot->invoke = sequencer_add_text_strip_invoke;
|
||||
ot->exec = sequencer_add_text_strip_exec;
|
||||
ot->poll = ED_operator_sequencer_active_editable;
|
||||
ot->poll_property = sequencer_add_text_strip_poll_property;
|
||||
ot->cancel = sequencer_add_free;
|
||||
|
||||
/* Flags. */
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
WM_operator_properties_filesel(ot,
|
||||
FILE_TYPE_FOLDER | FILE_TYPE_TEXT,
|
||||
FILE_SPECIAL,
|
||||
FILE_OPENFILE,
|
||||
WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH | WM_FILESEL_FILES |
|
||||
WM_FILESEL_DIRECTORY,
|
||||
FILE_DEFAULTDISPLAY,
|
||||
FILE_SORT_DEFAULT);
|
||||
sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_LENGTH | SEQPROP_MOVE);
|
||||
prop = RNA_def_string(
|
||||
ot->srna, "text", nullptr, 0, "Text", "Initialize the strip with this text");
|
||||
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Add Effect Strip
|
||||
* \{ */
|
||||
|
|
@ -2049,16 +2206,22 @@ static wmOperatorStatus sequencer_add_effect_strip_invoke(bContext *C,
|
|||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
sequencer_add_init(C, op);
|
||||
|
||||
int prop_flag = SEQPROP_LENGTH;
|
||||
/* When invoking an effect strip which uses inputs, skip guessing of the channel. */
|
||||
StripType type = StripType(RNA_enum_get(op->ptr, "type"));
|
||||
if (is_op_for_effect_with_inputs(CTX_data_sequencer_scene(C), type)) {
|
||||
prop_flag |= SEQPROP_NOCHAN;
|
||||
}
|
||||
if (is_drag_and_drop(op, event)) {
|
||||
prop_flag |= SEQPROP_NOPATHS;
|
||||
}
|
||||
|
||||
sequencer_generic_invoke_xy__internal(C, op, prop_flag, type, event);
|
||||
|
||||
return sequencer_add_effect_strip_exec(C, op);
|
||||
const wmOperatorStatus retval = sequencer_add_effect_strip_exec(C, op);
|
||||
sequencer_add_free(C, op);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static bool sequencer_add_effect_strip_poll_property(const bContext *C,
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_sound_types.h"
|
||||
#include "DNA_text_types.h"
|
||||
|
||||
#include "BLI_listbase.hh"
|
||||
#include "BLI_math_base_c.hh"
|
||||
|
|
@ -25,6 +26,7 @@
|
|||
#include "BKE_main.hh"
|
||||
#include "BKE_mask.hh"
|
||||
#include "BKE_movieclip.hh"
|
||||
#include "BKE_text.h"
|
||||
|
||||
#include "SEQ_add.hh"
|
||||
#include "SEQ_channels.hh"
|
||||
|
|
@ -192,6 +194,26 @@ static bool mask_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
|
|||
return false;
|
||||
}
|
||||
|
||||
static bool is_text(wmDrag *drag)
|
||||
{
|
||||
if (drag->type == WM_DRAG_PATH) {
|
||||
return WM_drag_get_paths(drag).size() == 1 &&
|
||||
BLI_path_extension_check(WM_drag_get_single_path(drag), ".txt");
|
||||
}
|
||||
return WM_drag_is_ID_type(drag, ID_TXT);
|
||||
}
|
||||
|
||||
static bool text_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event)
|
||||
{
|
||||
if (is_text(drag) && (drag->type != WM_DRAG_PATH ||
|
||||
test_single_file_handler_poll(C, drag, "SEQUENCER_FH_text_strip")))
|
||||
{
|
||||
return generic_poll_operations(C, event, TH_SEQ_TEXT);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool is_sound(wmDrag *drag)
|
||||
{
|
||||
if (drag->type == WM_DRAG_PATH) {
|
||||
|
|
@ -365,6 +387,12 @@ static void sequencer_drop_copy(bContext *C, wmDrag *drag, wmDropBox *drop)
|
|||
Main *bmain = CTX_data_main(C);
|
||||
RNA_enum_set(drop->ptr, "mask", BLI_findindex(&bmain->masks, id));
|
||||
}
|
||||
else if (id_type == ID_TXT) {
|
||||
size_t buf_len;
|
||||
char *buf = txt_to_buf(id_cast<Text *>(id), &buf_len);
|
||||
RNA_string_set(drop->ptr, "text", buf);
|
||||
MEM_delete(buf);
|
||||
}
|
||||
else if (id_type == ID_SO) {
|
||||
bSound *sound = id_cast<bSound *>(id);
|
||||
RNA_string_set(drop->ptr, "filepath", sound->filepath);
|
||||
|
|
@ -778,6 +806,20 @@ static void mask_drop_on_enter(wmDropBox *drop, wmDrag *drag)
|
|||
coords->only_audio = false;
|
||||
}
|
||||
|
||||
static void text_drop_on_enter(wmDropBox *drop, wmDrag * /*drag*/)
|
||||
{
|
||||
if (generic_drop_draw_handling(drop)) {
|
||||
return;
|
||||
}
|
||||
|
||||
SeqDropCoords *coords = static_cast<SeqDropCoords *>(drop->draw_data);
|
||||
coords->strip_length = seq::default_strip_length(coords->fps);
|
||||
coords->num_channels = 1;
|
||||
coords->num_audio = 0;
|
||||
coords->playback_rate = 0.0f;
|
||||
coords->only_audio = false;
|
||||
}
|
||||
|
||||
static void sequencer_drop_on_exit(wmDropBox *drop, wmDrag * /*drag*/)
|
||||
{
|
||||
SeqDropCoords *coords = static_cast<SeqDropCoords *>(drop->draw_data);
|
||||
|
|
@ -845,6 +887,13 @@ static void sequencer_dropboxes_add_to_lb(ListBaseT<wmDropBox> *lb)
|
|||
drop->on_enter = mask_drop_on_enter;
|
||||
drop->on_exit = sequencer_drop_on_exit;
|
||||
|
||||
drop = WM_dropbox_add(
|
||||
lb, "SEQUENCER_OT_text_strip_add", text_drop_poll, sequencer_drop_copy, nullptr, nullptr);
|
||||
drop->draw_droptip = nop_draw_droptip_fn;
|
||||
drop->draw_in_view = draw_strip_in_view;
|
||||
drop->on_enter = text_drop_on_enter;
|
||||
drop->on_exit = sequencer_drop_on_exit;
|
||||
|
||||
drop = WM_dropbox_add(
|
||||
lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy, nullptr, nullptr);
|
||||
drop->draw_droptip = nop_draw_droptip_fn;
|
||||
|
|
@ -898,6 +947,11 @@ static bool mask_drop_preview_poll(bContext * /*C*/, wmDrag *drag, const wmEvent
|
|||
return WM_drag_is_ID_type(drag, ID_MSK);
|
||||
}
|
||||
|
||||
static bool text_drop_preview_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
{
|
||||
return is_text(drag);
|
||||
}
|
||||
|
||||
static bool sound_drop_preview_poll(bContext * /*C*/, wmDrag *drag, const wmEvent * /*event*/)
|
||||
{
|
||||
if (drag->type == WM_DRAG_PATH) {
|
||||
|
|
@ -947,6 +1001,13 @@ static void sequencer_preview_dropboxes_add_to_lb(ListBaseT<wmDropBox> *lb)
|
|||
nullptr,
|
||||
nullptr);
|
||||
|
||||
WM_dropbox_add(lb,
|
||||
"SEQUENCER_OT_text_strip_add",
|
||||
text_drop_preview_poll,
|
||||
sequencer_drop_copy,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
WM_dropbox_add(lb,
|
||||
"SEQUENCER_OT_sound_strip_add",
|
||||
sound_drop_preview_poll,
|
||||
|
|
|
|||
|
|
@ -326,6 +326,7 @@ void SEQUENCER_OT_movieclip_strip_add(wmOperatorType *ot);
|
|||
void SEQUENCER_OT_mask_strip_add(wmOperatorType *ot);
|
||||
void SEQUENCER_OT_sound_strip_add(wmOperatorType *ot);
|
||||
void SEQUENCER_OT_image_strip_add(wmOperatorType *ot);
|
||||
void SEQUENCER_OT_text_strip_add(wmOperatorType *ot);
|
||||
void SEQUENCER_OT_effect_strip_add(wmOperatorType *ot);
|
||||
void SEQUENCER_OT_add_scene_strip_from_scene_asset(wmOperatorType *ot);
|
||||
|
||||
|
|
|
|||
|
|
@ -118,6 +118,7 @@ void sequencer_operatortypes()
|
|||
WM_operatortype_append(SEQUENCER_OT_movie_strip_add);
|
||||
WM_operatortype_append(SEQUENCER_OT_sound_strip_add);
|
||||
WM_operatortype_append(SEQUENCER_OT_image_strip_add);
|
||||
WM_operatortype_append(SEQUENCER_OT_text_strip_add);
|
||||
WM_operatortype_append(SEQUENCER_OT_effect_strip_add);
|
||||
WM_operatortype_append(SEQUENCER_OT_add_scene_strip_from_scene_asset);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue