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:
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
|
@ -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):
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue