Add background rectangle option to video sequencer Text strip

This adds a Box option to the Text strip's style properties, plus related Box Margin value:

{F9208309}

When enabled the text is placed on top of a solid-filled rectangle of a chosen color, as shown below:

{F9208324}

When the box option is disabled the text strip works the same as it does now. When the box option is enabled the meaning of the Shadow option changes to provide a drop-shadow on the rectangle (and not on the text itself). The latter made more sense to me.

The box margin is specified as a fraction of the image width. The offset of the drop-down box shadow is fixed to a specific fraction of the image width as well.

I tested this feature on a movie of a couple of minutes containing dozens of text strips (all with box background), edge cases like multi-line strings and text overlapping the image edges.

Reviewed By: ISS

Differential Revision: https://developer.blender.org/D9468
This commit is contained in:
Paul Melis 2020-11-06 15:42:52 +01:00 committed by Richard Antalik
parent f6524aaa80
commit 235c309e5f
Notes: blender-bot 2023-02-14 05:36:11 +01:00
Referenced by commit d581c1b304, UI: Correct label naming mistake for VSE text strip box background
4 changed files with 83 additions and 14 deletions

View File

@ -1187,6 +1187,21 @@ class SEQUENCER_PT_effect_text_style(SequencerButtonsPanel, Panel):
subsub.active = strip.use_shadow and (not strip.mute)
subsub.prop(strip, "shadow_color", text="")
row.prop_decorator(strip, "shadow_color")
row = layout.row(align=True, heading="Box")
row.use_property_decorate = False
sub = row.row(align=True)
sub.prop(strip, "use_box", text="")
subsub = sub.row(align=True)
subsub.active = strip.use_box and (not strip.mute)
subsub.prop(strip, "box_color", text="")
row.prop_decorator(strip, "box_color")
row = layout.row(align=True, heading="Box Margin")
row.use_property_decorate = False
sub = row.row(align=True)
sub.prop(strip, "box_margin")
sub.active = strip.use_box and (not strip.mute)
class SEQUENCER_PT_source(SequencerButtonsPanel, Panel):

View File

@ -341,17 +341,19 @@ typedef struct TextVars {
VFont *text_font;
int text_blf_id;
int text_size;
float color[4], shadow_color[4];
float color[4], shadow_color[4], box_color[4];
float loc[2];
float wrap_width;
float box_margin;
char flag;
char align, align_y;
char _pad[1];
char _pad[5];
} TextVars;
/* TextVars.flag */
enum {
SEQ_TEXT_SHADOW = (1 << 0),
SEQ_TEXT_BOX = (1 << 1),
};
/* TextVars.align */

View File

@ -1512,12 +1512,14 @@ static void rna_def_strip_proxy(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_proxy_custom_directory", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "storage", SEQ_STORAGE_PROXY_CUSTOM_DIR);
RNA_def_property_ui_text(prop, "Proxy Custom Directory", "Use a custom directory to store data");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "use_proxy_custom_file", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "storage", SEQ_STORAGE_PROXY_CUSTOM_FILE);
RNA_def_property_ui_text(prop, "Proxy Custom File", "Use a custom file to read proxy data from");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
}
static void rna_def_color_balance(BlenderRNA *brna)
@ -2181,7 +2183,8 @@ static void rna_def_proxy(StructRNA *srna)
RNA_def_property_ui_text(
prop, "Use Proxy / Timecode", "Use a preview proxy and/or time-code index for this strip");
RNA_def_property_boolean_funcs(prop, NULL, "rna_Sequence_use_proxy_set");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
prop = RNA_def_property(srna, "proxy", PROP_POINTER, PROP_NONE);
RNA_def_property_pointer_sdna(prop, NULL, "strip->proxy");
@ -2864,6 +2867,11 @@ static void rna_def_text(StructRNA *srna)
RNA_def_property_ui_text(prop, "Shadow Color", "");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "box_color", PROP_FLOAT, PROP_COLOR_GAMMA);
RNA_def_property_float_sdna(prop, NULL, "box_color");
RNA_def_property_ui_text(prop, "Box Color", "");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "location", PROP_FLOAT, PROP_XYZ);
RNA_def_property_float_sdna(prop, NULL, "loc");
RNA_def_property_ui_text(prop, "Location", "Location of the text");
@ -2878,6 +2886,14 @@ static void rna_def_text(StructRNA *srna)
RNA_def_property_ui_range(prop, 0.0, 1.0, 1, -1);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "box_margin", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "box_margin");
RNA_def_property_ui_text(prop, "Box Margin", "Box margin as factor of image width");
RNA_def_property_range(prop, 0, 1.0);
RNA_def_property_ui_range(prop, 0.0, 1.0, 1, -1);
RNA_def_property_float_default(prop, 0.01f);
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "align");
RNA_def_property_enum_items(prop, text_align_x_items);
@ -2900,6 +2916,11 @@ static void rna_def_text(StructRNA *srna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_TEXT_SHADOW);
RNA_def_property_ui_text(prop, "Shadow", "Display shadow behind text");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
prop = RNA_def_property(srna, "use_box", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_TEXT_BOX);
RNA_def_property_ui_text(prop, "Shadow", "Display colored box behind text");
RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update");
}
static void rna_def_color_mix(StructRNA *srna)

View File

@ -3788,6 +3788,11 @@ static void init_text_effect(Sequence *seq)
copy_v4_fl(data->color, 1.0f);
data->shadow_color[3] = 1.0f;
data->box_color[0] = 0.5f;
data->box_color[1] = 0.5f;
data->box_color[2] = 0.5f;
data->box_color[3] = 1.0f;
data->box_margin = 0.01f;
BLI_strncpy(data->text, "Text", sizeof(data->text));
@ -3929,18 +3934,18 @@ static ImBuf *do_text_effect(const SeqRenderData *context,
x = (data->loc[0] * width);
y = (data->loc[1] * height) + y_ofs;
/* vars for calculating wordwrap and optional box */
struct {
struct ResultBLF info;
rctf rect;
} wrap;
BLF_boundbox_ex(font, data->text, sizeof(data->text), &wrap.rect, &wrap.info);
if ((data->align == SEQ_TEXT_ALIGN_X_LEFT) && (data->align_y == SEQ_TEXT_ALIGN_Y_TOP)) {
y -= line_height;
}
else {
/* vars for calculating wordwrap */
struct {
struct ResultBLF info;
rctf rect;
} wrap;
BLF_boundbox_ex(font, data->text, sizeof(data->text), &wrap.rect, &wrap.info);
if (data->align == SEQ_TEXT_ALIGN_X_RIGHT) {
x -= BLI_rctf_size_x(&wrap.rect);
}
@ -3959,8 +3964,34 @@ static ImBuf *do_text_effect(const SeqRenderData *context,
}
}
if (data->flag & SEQ_TEXT_BOX) {
if (out->rect) {
const int margin = data->box_margin * width;
const int minx = x + wrap.rect.xmin - margin;
const int maxx = x + wrap.rect.xmax + margin;
const int miny = y + wrap.rect.ymin - margin;
const int maxy = y + wrap.rect.ymax + margin;
if (data->flag & SEQ_TEXT_SHADOW) {
/* draw a shadow behind the box */
int shadow_offset = 0.005f * width;
if (shadow_offset == 0) {
shadow_offset = 1;
}
IMB_rectfill_area_replace(out,
data->shadow_color,
minx + shadow_offset,
miny - shadow_offset,
maxx + shadow_offset,
maxy - shadow_offset);
}
IMB_rectfill_area_replace(out, data->box_color, minx, miny, maxx, maxy);
}
}
/* BLF_SHADOW won't work with buffers, instead use cheap shadow trick */
if (data->flag & SEQ_TEXT_SHADOW) {
else if (data->flag & SEQ_TEXT_SHADOW) {
int fontx, fonty;
fontx = BLF_width_max(font);
fonty = line_height;