[Text Server] Improve object (image/table) inline alignment.

This commit is contained in:
bruvzg 2021-06-14 10:11:37 +03:00
parent e010e05b3d
commit 7c3c5603d0
22 changed files with 449 additions and 279 deletions

View File

@ -133,6 +133,19 @@ void register_global_constants() {
BIND_CORE_ENUM_CONSTANT(VALIGN_CENTER);
BIND_CORE_ENUM_CONSTANT(VALIGN_BOTTOM);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TOP_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_CENTER_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_BOTTOM_TO);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TO_TOP);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TO_CENTER);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TO_BASELINE);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TO_BOTTOM);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_TOP);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_CENTER);
BIND_CORE_ENUM_CONSTANT(INLINE_ALIGN_BOTTOM);
// huge list of keys
BIND_CORE_CONSTANT(SPKEY);

View File

@ -81,6 +81,26 @@ enum VAlign {
VALIGN_BOTTOM
};
enum InlineAlign {
// Image alignment points.
INLINE_ALIGN_TOP_TO = 0b0000,
INLINE_ALIGN_CENTER_TO = 0b0001,
INLINE_ALIGN_BOTTOM_TO = 0b0010,
INLINE_ALIGN_IMAGE_MASK = 0b0011,
// Text alignment points.
INLINE_ALIGN_TO_TOP = 0b0000,
INLINE_ALIGN_TO_CENTER = 0b0100,
INLINE_ALIGN_TO_BASELINE = 0b1000,
INLINE_ALIGN_TO_BOTTOM = 0b1100,
INLINE_ALIGN_TEXT_MASK = 0b1100,
// Presets.
INLINE_ALIGN_TOP = INLINE_ALIGN_TOP_TO | INLINE_ALIGN_TO_TOP,
INLINE_ALIGN_CENTER = INLINE_ALIGN_CENTER_TO | INLINE_ALIGN_TO_CENTER,
INLINE_ALIGN_BOTTOM = INLINE_ALIGN_BOTTOM_TO | INLINE_ALIGN_TO_BOTTOM
};
enum Side {
SIDE_LEFT,
SIDE_TOP,

View File

@ -101,6 +101,7 @@ VARIANT_ENUM_CAST(MouseButton);
VARIANT_ENUM_CAST(Orientation);
VARIANT_ENUM_CAST(HAlign);
VARIANT_ENUM_CAST(VAlign);
VARIANT_ENUM_CAST(InlineAlign);
VARIANT_ENUM_CAST(PropertyHint);
VARIANT_ENUM_CAST(PropertyUsageFlags);
VARIANT_ENUM_CAST(Variant::Type);

View File

@ -1128,6 +1128,36 @@
<constant name="VALIGN_BOTTOM" value="2" enum="VAlign">
Vertical bottom alignment, usually for text-derived classes.
</constant>
<constant name="INLINE_ALIGN_TOP_TO" value="0" enum="InlineAlign">
Aligns the top of the inline object (e.g. image, table) to the position of the text specified by [code]INLINE_ALIGN_TO_*[/code] constant.
</constant>
<constant name="INLINE_ALIGN_CENTER_TO" value="1" enum="InlineAlign">
Aligns the center of the inline object (e.g. image, table) to the position of the text specified by [code]INLINE_ALIGN_TO_*[/code] constant.
</constant>
<constant name="INLINE_ALIGN_BOTTOM_TO" value="2" enum="InlineAlign">
Aligns the bottom of the inline object (e.g. image, table) to the position of the text specified by [code]INLINE_ALIGN_TO_*[/code] constant.
</constant>
<constant name="INLINE_ALIGN_TO_TOP" value="0" enum="InlineAlign">
Aligns the position of the inline object (e.g. image, table) specified by [code]INLINE_ALIGN_*_TO[/code] constant to the top of the text.
</constant>
<constant name="INLINE_ALIGN_TO_CENTER" value="4" enum="InlineAlign">
Aligns the position of the inline object (e.g. image, table) specified by [code]INLINE_ALIGN_*_TO[/code] constant to the center of the text.
</constant>
<constant name="INLINE_ALIGN_TO_BASELINE" value="8" enum="InlineAlign">
Aligns the position of the inline object (e.g. image, table) specified by [code]INLINE_ALIGN_*_TO[/code] constant to the baseline of the text.
</constant>
<constant name="INLINE_ALIGN_TO_BOTTOM" value="12" enum="InlineAlign">
Aligns inline object (e.g. image, table) to the bottom of the text.
</constant>
<constant name="INLINE_ALIGN_TOP" value="0" enum="InlineAlign">
Aligns top of the inline object (e.g. image, table) to the top of the text. Equvalent to [code]INLINE_ALIGN_TOP_TO | INLINE_ALIGN_TO_TOP[/code].
</constant>
<constant name="INLINE_ALIGN_CENTER" value="5" enum="InlineAlign">
Aligns center of the inline object (e.g. image, table) to the center of the text. Equvalent to [code]INLINE_ALIGN_CENTER_TO | INLINE_ALIGN_TO_CENTER[/code].
</constant>
<constant name="INLINE_ALIGN_BOTTOM" value="14" enum="InlineAlign">
Aligns bottom of the inline object (e.g. image, table) to the bottom of the text. Equvalent to [code]INLINE_ALIGN_BOTTOM_TO | INLINE_ALIGN_TO_BOTTOM[/code].
</constant>
<constant name="SPKEY" value="16777216">
Keycodes with this bit applied are non-printable.
</constant>

View File

@ -21,7 +21,7 @@
<argument index="1" name="width" type="int" default="0" />
<argument index="2" name="height" type="int" default="0" />
<argument index="3" name="color" type="Color" default="Color(1, 1, 1, 1)" />
<argument index="4" name="inline_align" type="int" enum="VAlign" default="0" />
<argument index="4" name="inline_align" type="int" enum="InlineAlign" default="5" />
<description>
Adds an image's opening and closing tags to the tag stack, optionally providing a [code]width[/code] and [code]height[/code] to resize the image and a [code]color[/code] to tint the image.
If [code]width[/code] or [code]height[/code] is set to 0, the image size will be adjusted in order to keep the original aspect ratio.
@ -288,7 +288,7 @@
<method name="push_table">
<return type="void" />
<argument index="0" name="columns" type="int" />
<argument index="1" name="inline_align" type="int" enum="VAlign" default="0" />
<argument index="1" name="inline_align" type="int" enum="InlineAlign" default="0" />
<description>
Adds a [code][table=columns,inline_align][/code] tag to the tag stack.
</description>

View File

@ -13,7 +13,7 @@
<return type="bool" />
<argument index="0" name="key" type="Variant" />
<argument index="1" name="size" type="Vector2" />
<argument index="2" name="inline_align" type="int" enum="VAlign" default="1" />
<argument index="2" name="inline_align" type="int" enum="InlineAlign" default="5" />
<argument index="3" name="length" type="int" default="1" />
<description>
Adds inline object to the text buffer, [code]key[/code] must be unique. In the text, object is represented as [code]length[/code] object replacement characters.
@ -122,7 +122,7 @@
<return type="bool" />
<argument index="0" name="key" type="Variant" />
<argument index="1" name="size" type="Vector2" />
<argument index="2" name="inline_align" type="int" enum="VAlign" default="1" />
<argument index="2" name="inline_align" type="int" enum="InlineAlign" default="5" />
<description>
Sets new size and alignment of embedded object.
</description>

View File

@ -13,7 +13,7 @@
<return type="bool" />
<argument index="0" name="key" type="Variant" />
<argument index="1" name="size" type="Vector2" />
<argument index="2" name="inline_align" type="int" enum="VAlign" default="1" />
<argument index="2" name="inline_align" type="int" enum="InlineAlign" default="5" />
<argument index="3" name="length" type="int" default="1" />
<description>
Adds inline object to the text buffer, [code]key[/code] must be unique. In the text, object is represented as [code]length[/code] object replacement characters.
@ -240,7 +240,7 @@
<return type="bool" />
<argument index="0" name="key" type="Variant" />
<argument index="1" name="size" type="Vector2" />
<argument index="2" name="inline_align" type="int" enum="VAlign" default="1" />
<argument index="2" name="inline_align" type="int" enum="InlineAlign" default="5" />
<description>
Sets new size and alignment of embedded object.
</description>

View File

@ -541,7 +541,7 @@
<argument index="0" name="shaped" type="RID" />
<argument index="1" name="key" type="Variant" />
<argument index="2" name="size" type="Vector2" />
<argument index="3" name="inline_align" type="int" enum="VAlign" default="1" />
<argument index="3" name="inline_align" type="int" enum="InlineAlign" default="5" />
<argument index="4" name="length" type="int" default="1" />
<description>
Adds inline object to the text buffer, [code]key[/code] must be unique. In the text, object is represented as [code]length[/code] object replacement characters.
@ -817,7 +817,7 @@
<argument index="0" name="shaped" type="RID" />
<argument index="1" name="key" type="Variant" />
<argument index="2" name="size" type="Vector2" />
<argument index="3" name="inline_align" type="int" enum="VAlign" default="1" />
<argument index="3" name="inline_align" type="int" enum="InlineAlign" default="5" />
<description>
Sets new size and alignment of embedded object.
</description>

View File

@ -449,12 +449,12 @@ bool TextServerGDNative::shaped_text_add_string(RID p_shaped, const String &p_te
return interface->shaped_text_add_string(data, (godot_rid *)&p_shaped, (const godot_string *)&p_text, (const godot_rid **)p_fonts.ptr(), p_size, (const godot_dictionary *)&p_opentype_features, (const godot_string *)&p_language);
}
bool TextServerGDNative::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
bool TextServerGDNative::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
ERR_FAIL_COND_V(interface == nullptr, false);
return interface->shaped_text_add_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align, p_length);
}
bool TextServerGDNative::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
bool TextServerGDNative::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
ERR_FAIL_COND_V(interface == nullptr, false);
return interface->shaped_text_resize_object(data, (godot_rid *)&p_shaped, (const godot_variant *)&p_key, (const godot_vector2 *)&p_size, (godot_int)p_inline_align);
}

View File

@ -154,8 +154,8 @@ public:
virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override;
virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;

View File

@ -1161,7 +1161,7 @@ bool TextServerAdvanced::shaped_text_add_string(RID p_shaped, const String &p_te
return true;
}
bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
_THREAD_SAFE_METHOD_
ShapedTextDataAdvanced *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@ -1191,7 +1191,7 @@ bool TextServerAdvanced::shaped_text_add_object(RID p_shaped, Variant p_key, con
return true;
}
bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@ -1222,34 +1222,10 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[key].rect.position.x = sd->width;
sd->width += sd->objects[key].rect.size.x;
switch (sd->objects[key].inline_align) {
case VALIGN_TOP: {
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
} break;
}
sd->glyphs.write[i].advance = sd->objects[key].rect.size.x;
} else {
sd->objects[key].rect.position.y = sd->width;
sd->width += sd->objects[key].rect.size.y;
switch (sd->objects[key].inline_align) {
case VALIGN_TOP: {
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
} break;
}
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
}
} else {
@ -1279,35 +1255,71 @@ bool TextServerAdvanced::shaped_text_resize_object(RID p_shaped, Variant p_key,
}
// Align embedded objects to baseline.
float full_ascent = sd->ascent;
float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.y = -(E->get().rect.size.y / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.y = sd->descent - E->get().rect.size.y;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.y = sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.y -= E->get().rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.y -= E->get().rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.y);
full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.x = -(E->get().rect.size.x / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.x = sd->descent - E->get().rect.size.x;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.x = sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.x -= E->get().rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.x -= E->get().rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.x);
full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
sd->ascent = full_ascent;
sd->descent = full_descent;
}
return true;
}
@ -1404,33 +1416,9 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->objects[key].rect.position.x = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.x;
switch (new_sd->objects[key].inline_align) {
case VALIGN_TOP: {
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
} break;
}
} else {
new_sd->objects[key].rect.position.y = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.y;
switch (new_sd->objects[key].inline_align) {
case VALIGN_TOP: {
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
} break;
}
}
} else {
if (prev_rid != gl.font_rid) {
@ -1464,37 +1452,72 @@ RID TextServerAdvanced::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
// Align embedded objects to baseline.
float full_ascent = new_sd->ascent;
float full_descent = new_sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -new_sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.y = -(E->get().rect.size.y / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.y = new_sd->descent - E->get().rect.size.y;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.y = new_sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.y -= E->get().rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.y -= E->get().rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.y);
full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -new_sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.x = -(E->get().rect.size.x / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.x = new_sd->descent - E->get().rect.size.x;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.x = new_sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.x -= E->get().rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.x -= E->get().rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.x);
full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
new_sd->ascent = full_ascent;
new_sd->descent = full_descent;
}
new_sd->valid = true;
return shaped_owner.make_rid(new_sd);
@ -2473,33 +2496,9 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[span.embedded_key].rect.position.x = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.x;
switch (sd->objects[span.embedded_key].inline_align) {
case VALIGN_TOP: {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
} break;
}
} else {
sd->objects[span.embedded_key].rect.position.y = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.y;
switch (sd->objects[span.embedded_key].inline_align) {
case VALIGN_TOP: {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
} break;
}
}
Glyph gl;
gl.start = span.start;
@ -2539,34 +2538,69 @@ bool TextServerAdvanced::shaped_text_shape(RID p_shaped) {
}
// Align embedded objects to baseline.
float full_ascent = sd->ascent;
float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.y = -(E->get().rect.size.y / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.y = sd->descent - E->get().rect.size.y;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.y = sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.y -= E->get().rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.y -= E->get().rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.y);
full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.x = -(E->get().rect.size.x / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.x = sd->descent - E->get().rect.size.x;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.x = sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.x -= E->get().rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.x -= E->get().rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.x);
full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
sd->ascent = full_ascent;
sd->descent = full_descent;
sd->valid = true;
return sd->valid;
}

View File

@ -216,8 +216,8 @@ public:
virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override;
virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;

View File

@ -661,7 +661,7 @@ bool TextServerFallback::shaped_text_add_string(RID p_shaped, const String &p_te
return true;
}
bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@ -691,7 +691,7 @@ bool TextServerFallback::shaped_text_add_object(RID p_shaped, Variant p_key, con
return true;
}
bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
_THREAD_SAFE_METHOD_
ShapedTextData *sd = shaped_owner.getornull(p_shaped);
ERR_FAIL_COND_V(!sd, false);
@ -724,34 +724,10 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[key].rect.position.x = sd->width;
sd->width += sd->objects[key].rect.size.x;
switch (sd->objects[key].inline_align) {
case VALIGN_TOP: {
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.y / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.y);
} break;
}
sd->glyphs.write[i].advance = sd->objects[key].rect.size.x;
} else {
sd->objects[key].rect.position.y = sd->width;
sd->width += sd->objects[key].rect.size.y;
switch (sd->objects[key].inline_align) {
case VALIGN_TOP: {
sd->ascent = MAX(sd->ascent, sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[key].rect.size.x / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[key].rect.size.x);
} break;
}
sd->glyphs.write[i].advance = sd->objects[key].rect.size.y;
}
} else {
@ -784,35 +760,71 @@ bool TextServerFallback::shaped_text_resize_object(RID p_shaped, Variant p_key,
}
// Align embedded objects to baseline.
float full_ascent = sd->ascent;
float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= sd->start) && (E->get().pos < sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.y = -(E->get().rect.size.y / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.y = sd->descent - E->get().rect.size.y;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.y = sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.y -= E->get().rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.y -= E->get().rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.y);
full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.x = -(E->get().rect.size.x / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.x = sd->descent - E->get().rect.size.x;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.x = sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.x -= E->get().rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.x -= E->get().rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.x);
full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
sd->ascent = full_ascent;
sd->descent = full_descent;
}
return true;
}
@ -869,33 +881,9 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
if (new_sd->orientation == ORIENTATION_HORIZONTAL) {
new_sd->objects[key].rect.position.x = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.x;
switch (new_sd->objects[key].inline_align) {
case VALIGN_TOP: {
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.y);
} break;
case VALIGN_CENTER: {
new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.y / 2));
new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.y);
} break;
}
} else {
new_sd->objects[key].rect.position.y = new_sd->width;
new_sd->width += new_sd->objects[key].rect.size.y;
switch (new_sd->objects[key].inline_align) {
case VALIGN_TOP: {
new_sd->ascent = MAX(new_sd->ascent, new_sd->objects[key].rect.size.x);
} break;
case VALIGN_CENTER: {
new_sd->ascent = MAX(new_sd->ascent, Math::round(new_sd->objects[key].rect.size.x / 2));
new_sd->descent = MAX(new_sd->descent, Math::round(new_sd->objects[key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
new_sd->descent = MAX(new_sd->descent, new_sd->objects[key].rect.size.x);
} break;
}
}
} else {
const FontDataFallback *fd = font_owner.getornull(gl.font_rid);
@ -923,35 +911,72 @@ RID TextServerFallback::shaped_text_substr(RID p_shaped, int p_start, int p_leng
}
}
// Align embedded objects to baseline.
float full_ascent = new_sd->ascent;
float full_descent = new_sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = new_sd->objects.front(); E; E = E->next()) {
if ((E->get().pos >= new_sd->start) && (E->get().pos < new_sd->end)) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -new_sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.y = -(E->get().rect.size.y / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.y = (-new_sd->ascent + new_sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.y = new_sd->descent - E->get().rect.size.y;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.y = new_sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.y -= E->get().rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.y -= E->get().rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.y);
full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -new_sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.x = -(E->get().rect.size.x / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.x = (-new_sd->ascent + new_sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.x = new_sd->descent - E->get().rect.size.x;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.x = new_sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.x -= E->get().rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.x -= E->get().rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.x);
full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
}
new_sd->ascent = full_ascent;
new_sd->descent = full_descent;
}
new_sd->valid = true;
@ -1336,33 +1361,9 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
sd->objects[span.embedded_key].rect.position.x = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.x;
switch (sd->objects[span.embedded_key].inline_align) {
case VALIGN_TOP: {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.y);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.y / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.y);
} break;
}
} else {
sd->objects[span.embedded_key].rect.position.y = sd->width;
sd->width += sd->objects[span.embedded_key].rect.size.y;
switch (sd->objects[span.embedded_key].inline_align) {
case VALIGN_TOP: {
sd->ascent = MAX(sd->ascent, sd->objects[span.embedded_key].rect.size.x);
} break;
case VALIGN_CENTER: {
sd->ascent = MAX(sd->ascent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
sd->descent = MAX(sd->descent, Math::round(sd->objects[span.embedded_key].rect.size.x / 2));
} break;
case VALIGN_BOTTOM: {
sd->descent = MAX(sd->descent, sd->objects[span.embedded_key].rect.size.x);
} break;
}
}
Glyph gl;
gl.start = span.start;
@ -1456,34 +1457,69 @@ bool TextServerFallback::shaped_text_shape(RID p_shaped) {
}
// Align embedded objects to baseline.
float full_ascent = sd->ascent;
float full_descent = sd->descent;
for (Map<Variant, ShapedTextData::EmbeddedObject>::Element *E = sd->objects.front(); E; E = E->next()) {
if (sd->orientation == ORIENTATION_HORIZONTAL) {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.y = -sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.y = -(E->get().rect.size.y / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.y = (-sd->ascent + sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.y = sd->descent - E->get().rect.size.y;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.y = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.y = sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.y -= E->get().rect.size.y;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.y -= E->get().rect.size.y / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.y);
full_descent = MAX(full_descent, E->get().rect.position.y + E->get().rect.size.y);
} else {
switch (E->get().inline_align) {
case VALIGN_TOP: {
switch (E->get().inline_align & INLINE_ALIGN_TEXT_MASK) {
case INLINE_ALIGN_TO_TOP: {
E->get().rect.position.x = -sd->ascent;
} break;
case VALIGN_CENTER: {
E->get().rect.position.x = -(E->get().rect.size.x / 2);
case INLINE_ALIGN_TO_CENTER: {
E->get().rect.position.x = (-sd->ascent + sd->descent) / 2;
} break;
case VALIGN_BOTTOM: {
E->get().rect.position.x = sd->descent - E->get().rect.size.x;
case INLINE_ALIGN_TO_BASELINE: {
E->get().rect.position.x = 0;
} break;
case INLINE_ALIGN_TO_BOTTOM: {
E->get().rect.position.x = sd->descent;
} break;
}
switch (E->get().inline_align & INLINE_ALIGN_IMAGE_MASK) {
case INLINE_ALIGN_BOTTOM_TO: {
E->get().rect.position.x -= E->get().rect.size.x;
} break;
case INLINE_ALIGN_CENTER_TO: {
E->get().rect.position.x -= E->get().rect.size.x / 2;
} break;
case INLINE_ALIGN_TOP_TO: {
//NOP
} break;
}
full_ascent = MAX(full_ascent, -E->get().rect.position.x);
full_descent = MAX(full_descent, E->get().rect.position.x + E->get().rect.size.x);
}
}
sd->ascent = full_ascent;
sd->descent = full_descent;
sd->valid = true;
return sd->valid;
}

View File

@ -165,8 +165,8 @@ public:
virtual bool shaped_text_get_preserve_control(RID p_shaped) const override;
virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override;
virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) override;
virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) override;
virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override;
virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override;
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override;
virtual RID shaped_text_get_parent(RID p_shaped) const override;

View File

@ -2289,7 +2289,7 @@ void RichTextLabel::_remove_item(Item *p_item, const int p_line, const int p_sub
}
}
void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, VAlign p_align) {
void RichTextLabel::add_image(const Ref<Texture2D> &p_image, const int p_width, const int p_height, const Color &p_color, InlineAlign p_align) {
if (current->type == ITEM_TABLE) {
return;
}
@ -2534,7 +2534,7 @@ void RichTextLabel::push_meta(const Variant &p_meta) {
_add_item(item, true);
}
void RichTextLabel::push_table(int p_columns, VAlign p_align) {
void RichTextLabel::push_table(int p_columns, InlineAlign p_align) {
ERR_FAIL_COND(p_columns < 1);
ItemTable *item = memnew(ItemTable);
@ -2897,18 +2897,35 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
columns = 1;
}
VAlign align = VALIGN_TOP;
if (subtag.size() > 1) {
int align = INLINE_ALIGN_TOP;
if (subtag.size() > 2) {
if (subtag[1] == "top" || subtag[1] == "t") {
align = VALIGN_TOP;
align = INLINE_ALIGN_TOP_TO;
} else if (subtag[1] == "center" || subtag[1] == "c") {
align = VALIGN_CENTER;
align = INLINE_ALIGN_CENTER_TO;
} else if (subtag[1] == "bottom" || subtag[1] == "b") {
align = VALIGN_BOTTOM;
align = INLINE_ALIGN_BOTTOM_TO;
}
if (subtag[2] == "top" || subtag[2] == "t") {
align |= INLINE_ALIGN_TO_TOP;
} else if (subtag[2] == "center" || subtag[2] == "c") {
align |= INLINE_ALIGN_TO_CENTER;
} else if (subtag[2] == "baseline" || subtag[2] == "l") {
align |= INLINE_ALIGN_TO_BASELINE;
} else if (subtag[2] == "bottom" || subtag[2] == "b") {
align |= INLINE_ALIGN_TO_BOTTOM;
}
} else if (subtag.size() > 1) {
if (subtag[1] == "top" || subtag[1] == "t") {
align = INLINE_ALIGN_TOP;
} else if (subtag[1] == "center" || subtag[1] == "c") {
align = INLINE_ALIGN_CENTER;
} else if (subtag[1] == "bottom" || subtag[1] == "b") {
align = INLINE_ALIGN_BOTTOM;
}
}
push_table(columns, align);
push_table(columns, (InlineAlign)align);
pos = brk_end + 1;
tag_stack.push_front("table");
} else if (tag == "cell") {
@ -3187,15 +3204,34 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
pos = end;
tag_stack.push_front(bbcode_name);
} else if (tag.begins_with("img")) {
VAlign align = VALIGN_TOP;
int align = INLINE_ALIGN_CENTER;
if (tag.begins_with("img=")) {
String al = tag.substr(4, tag.length());
if (al == "top" || al == "t") {
align = VALIGN_TOP;
} else if (al == "center" || al == "c") {
align = VALIGN_CENTER;
} else if (al == "bottom" || al == "b") {
align = VALIGN_BOTTOM;
Vector<String> subtag = tag.substr(4, tag.length()).split(",");
if (subtag.size() > 1) {
if (subtag[0] == "top" || subtag[0] == "t") {
align = INLINE_ALIGN_TOP_TO;
} else if (subtag[0] == "center" || subtag[0] == "c") {
align = INLINE_ALIGN_CENTER_TO;
} else if (subtag[0] == "bottom" || subtag[0] == "b") {
align = INLINE_ALIGN_BOTTOM_TO;
}
if (subtag[1] == "top" || subtag[1] == "t") {
align |= INLINE_ALIGN_TO_TOP;
} else if (subtag[1] == "center" || subtag[1] == "c") {
align |= INLINE_ALIGN_TO_CENTER;
} else if (subtag[1] == "baseline" || subtag[1] == "l") {
align |= INLINE_ALIGN_TO_BASELINE;
} else if (subtag[1] == "bottom" || subtag[1] == "b") {
align |= INLINE_ALIGN_TO_BOTTOM;
}
} else if (subtag.size() > 0) {
if (subtag[0] == "top" || subtag[0] == "t") {
align = INLINE_ALIGN_TOP;
} else if (subtag[0] == "center" || subtag[0] == "c") {
align = INLINE_ALIGN_CENTER;
} else if (subtag[0] == "bottom" || subtag[0] == "b") {
align = INLINE_ALIGN_BOTTOM;
}
}
}
@ -3236,7 +3272,7 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
}
}
add_image(texture, width, height, color, align);
add_image(texture, width, height, color, (InlineAlign)align);
}
pos = end;
@ -3961,7 +3997,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_text"), &RichTextLabel::get_text);
ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
ClassDB::bind_method(D_METHOD("set_text", "text"), &RichTextLabel::set_text);
ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(VALIGN_TOP));
ClassDB::bind_method(D_METHOD("add_image", "image", "width", "height", "color", "inline_align"), &RichTextLabel::add_image, DEFVAL(0), DEFVAL(0), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(INLINE_ALIGN_CENTER));
ClassDB::bind_method(D_METHOD("newline"), &RichTextLabel::add_newline);
ClassDB::bind_method(D_METHOD("remove_line", "line"), &RichTextLabel::remove_line);
ClassDB::bind_method(D_METHOD("push_font", "font"), &RichTextLabel::push_font);
@ -3981,7 +4017,7 @@ void RichTextLabel::_bind_methods() {
ClassDB::bind_method(D_METHOD("push_meta", "data"), &RichTextLabel::push_meta);
ClassDB::bind_method(D_METHOD("push_underline"), &RichTextLabel::push_underline);
ClassDB::bind_method(D_METHOD("push_strikethrough"), &RichTextLabel::push_strikethrough);
ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align"), &RichTextLabel::push_table, DEFVAL(VALIGN_TOP));
ClassDB::bind_method(D_METHOD("push_table", "columns", "inline_align"), &RichTextLabel::push_table, DEFVAL(INLINE_ALIGN_TOP));
ClassDB::bind_method(D_METHOD("push_dropcap", "string", "font", "size", "dropcap_margins", "color", "outline_size", "outline_color"), &RichTextLabel::push_dropcap, DEFVAL(Rect2()), DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(Color(0, 0, 0, 0)));
ClassDB::bind_method(D_METHOD("set_table_column_expand", "column", "expand", "ratio"), &RichTextLabel::set_table_column_expand);
ClassDB::bind_method(D_METHOD("set_cell_row_background_color", "odd_row_bg", "even_row_bg"), &RichTextLabel::set_cell_row_background_color);

View File

@ -161,7 +161,7 @@ private:
struct ItemImage : public Item {
Ref<Texture2D> image;
VAlign inline_align = VALIGN_TOP;
InlineAlign inline_align = INLINE_ALIGN_CENTER;
Size2 size;
Color color;
ItemImage() { type = ITEM_IMAGE; }
@ -248,7 +248,7 @@ private:
int total_width = 0;
int total_height = 0;
VAlign inline_align = VALIGN_TOP;
InlineAlign inline_align = INLINE_ALIGN_TOP;
ItemTable() { type = ITEM_TABLE; }
};
@ -463,7 +463,7 @@ private:
public:
String get_text();
void add_text(const String &p_text);
void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), VAlign p_align = VALIGN_TOP);
void add_image(const Ref<Texture2D> &p_image, const int p_width = 0, const int p_height = 0, const Color &p_color = Color(1.0, 1.0, 1.0), InlineAlign p_align = INLINE_ALIGN_CENTER);
void add_newline();
bool remove_line(const int p_line);
void push_dropcap(const String &p_string, const Ref<Font> &p_font, int p_size, const Rect2 &p_dropcap_margins = Rect2(), const Color &p_color = Color(1, 1, 1), int p_ol_size = 0, const Color &p_ol_color = Color(0, 0, 0, 0));
@ -484,7 +484,7 @@ public:
void push_indent(int p_level);
void push_list(int p_level, ListType p_list, bool p_capitalize);
void push_meta(const Variant &p_meta);
void push_table(int p_columns, VAlign p_align = VALIGN_TOP);
void push_table(int p_columns, InlineAlign p_align = INLINE_ALIGN_TOP);
void push_fade(int p_start_index, int p_length);
void push_shake(int p_strength, float p_rate);
void push_wave(float p_frequency, float p_amplitude);

View File

@ -56,8 +56,8 @@ void TextLine::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bidi_override", "override"), &TextLine::_set_bidi_override);
ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language"), &TextLine::add_string, DEFVAL(Dictionary()), DEFVAL(""));
ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextLine::add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1));
ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextLine::resize_object, DEFVAL(VALIGN_CENTER));
ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextLine::add_object, DEFVAL(INLINE_ALIGN_CENTER), DEFVAL(1));
ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextLine::resize_object, DEFVAL(INLINE_ALIGN_CENTER));
ClassDB::bind_method(D_METHOD("set_width", "width"), &TextLine::set_width);
ClassDB::bind_method(D_METHOD("get_width"), &TextLine::get_width);
@ -175,13 +175,13 @@ bool TextLine::add_string(const String &p_text, const Ref<Font> &p_fonts, int p_
return res;
}
bool TextLine::add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
bool TextLine::add_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length);
dirty = true;
return res;
}
bool TextLine::resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
bool TextLine::resize_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
const_cast<TextLine *>(this)->_shape();
return TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align);
}

View File

@ -76,8 +76,8 @@ public:
bool get_preserve_control() const;
bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "");
bool add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1);
bool resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER);
bool add_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1);
bool resize_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER);
void set_align(HAlign p_align);
HAlign get_align() const;

View File

@ -59,8 +59,8 @@ void TextParagraph::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_dropcap"), &TextParagraph::clear_dropcap);
ClassDB::bind_method(D_METHOD("add_string", "text", "fonts", "size", "opentype_features", "language"), &TextParagraph::add_string, DEFVAL(Dictionary()), DEFVAL(""));
ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextParagraph::add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1));
ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextParagraph::resize_object, DEFVAL(VALIGN_CENTER));
ClassDB::bind_method(D_METHOD("add_object", "key", "size", "inline_align", "length"), &TextParagraph::add_object, DEFVAL(INLINE_ALIGN_CENTER), DEFVAL(1));
ClassDB::bind_method(D_METHOD("resize_object", "key", "size", "inline_align"), &TextParagraph::resize_object, DEFVAL(INLINE_ALIGN_CENTER));
ClassDB::bind_method(D_METHOD("set_align", "align"), &TextParagraph::set_align);
ClassDB::bind_method(D_METHOD("get_align"), &TextParagraph::get_align);
@ -290,13 +290,13 @@ void TextParagraph::set_bidi_override(const Vector<Vector2i> &p_override) {
dirty_lines = true;
}
bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align, int p_length) {
bool TextParagraph::add_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) {
bool res = TS->shaped_text_add_object(rid, p_key, p_size, p_inline_align, p_length);
dirty_lines = true;
return res;
}
bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align) {
bool TextParagraph::resize_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) {
bool res = TS->shaped_text_resize_object(rid, p_key, p_size, p_inline_align);
dirty_lines = true;
return res;

View File

@ -86,8 +86,8 @@ public:
void clear_dropcap();
bool add_string(const String &p_text, const Ref<Font> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "");
bool add_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1);
bool resize_object(Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER);
bool add_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1);
bool resize_object(Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER);
void set_align(HAlign p_align);
HAlign get_align() const;

View File

@ -314,8 +314,8 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("shaped_text_get_preserve_control", "shaped"), &TextServer::shaped_text_get_preserve_control);
ClassDB::bind_method(D_METHOD("shaped_text_add_string", "shaped", "text", "fonts", "size", "opentype_features", "language"), &TextServer::shaped_text_add_string, DEFVAL(Dictionary()), DEFVAL(""));
ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(VALIGN_CENTER), DEFVAL(1));
ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(VALIGN_CENTER));
ClassDB::bind_method(D_METHOD("shaped_text_add_object", "shaped", "key", "size", "inline_align", "length"), &TextServer::shaped_text_add_object, DEFVAL(INLINE_ALIGN_CENTER), DEFVAL(1));
ClassDB::bind_method(D_METHOD("shaped_text_resize_object", "shaped", "key", "size", "inline_align"), &TextServer::shaped_text_resize_object, DEFVAL(INLINE_ALIGN_CENTER));
ClassDB::bind_method(D_METHOD("shaped_text_substr", "shaped", "start", "length"), &TextServer::shaped_text_substr);
ClassDB::bind_method(D_METHOD("shaped_text_get_parent", "shaped"), &TextServer::shaped_text_get_parent);

View File

@ -181,7 +181,7 @@ public:
struct EmbeddedObject {
int pos = 0;
VAlign inline_align = VALIGN_TOP;
InlineAlign inline_align = INLINE_ALIGN_CENTER;
Rect2 rect;
};
Map<Variant, EmbeddedObject> objects;
@ -332,8 +332,8 @@ public:
virtual bool shaped_text_get_preserve_control(RID p_shaped) const = 0;
virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") = 0;
virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER, int p_length = 1) = 0;
virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, VAlign p_inline_align = VALIGN_CENTER) = 0;
virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) = 0;
virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) = 0;
virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const = 0; // Copy shaped substring (e.g. line break) without reshaping, but correctly reordered, preservers range.
virtual RID shaped_text_get_parent(RID p_shaped) const = 0;