Implement BiDi override mode for GDScript source.
This commit is contained in:
parent
b5f3ac522e
commit
5361ec9f43
@ -196,12 +196,12 @@
|
|||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="_structured_text_parser" qualifiers="virtual const">
|
<method name="_structured_text_parser" qualifiers="virtual const">
|
||||||
<return type="Vector2i[]" />
|
<return type="Vector3i[]" />
|
||||||
<param index="0" name="args" type="Array" />
|
<param index="0" name="args" type="Array" />
|
||||||
<param index="1" name="text" type="String" />
|
<param index="1" name="text" type="String" />
|
||||||
<description>
|
<description>
|
||||||
User defined BiDi algorithm override function.
|
User defined BiDi algorithm override function.
|
||||||
Returns an [Array] of [Vector2i] text ranges, in the left-to-right order. Ranges should cover full source [param text] without overlaps. BiDi algorithm will be used on each range separately.
|
Returns an [Array] of [Vector3i] text ranges and text base directions, in the left-to-right order. Ranges should cover full source [param text] without overlaps. BiDi algorithm will be used on each range separately.
|
||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="accept_event">
|
<method name="accept_event">
|
||||||
|
@ -1042,7 +1042,7 @@
|
|||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="parse_structured_text" qualifiers="const">
|
<method name="parse_structured_text" qualifiers="const">
|
||||||
<return type="Vector2i[]" />
|
<return type="Vector3i[]" />
|
||||||
<param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
|
<param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
|
||||||
<param index="1" name="args" type="Array" />
|
<param index="1" name="args" type="Array" />
|
||||||
<param index="2" name="text" type="String" />
|
<param index="2" name="text" type="String" />
|
||||||
@ -1634,6 +1634,9 @@
|
|||||||
<constant name="DIRECTION_RTL" value="2" enum="Direction">
|
<constant name="DIRECTION_RTL" value="2" enum="Direction">
|
||||||
Text is written from right to left.
|
Text is written from right to left.
|
||||||
</constant>
|
</constant>
|
||||||
|
<constant name="DIRECTION_INHERITED" value="3" enum="Direction">
|
||||||
|
Text writing direction is the same as base string writing direction. Used for BiDi override only.
|
||||||
|
</constant>
|
||||||
<constant name="ORIENTATION_HORIZONTAL" value="0" enum="Orientation">
|
<constant name="ORIENTATION_HORIZONTAL" value="0" enum="Orientation">
|
||||||
Text is written horizontally.
|
Text is written horizontally.
|
||||||
</constant>
|
</constant>
|
||||||
@ -1881,7 +1884,7 @@
|
|||||||
Font have fixed-width characters.
|
Font have fixed-width characters.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="STRUCTURED_TEXT_DEFAULT" value="0" enum="StructuredTextParser">
|
<constant name="STRUCTURED_TEXT_DEFAULT" value="0" enum="StructuredTextParser">
|
||||||
Use default behavior. Same as [constant STRUCTURED_TEXT_NONE] unless specified otherwise in the control description.
|
Use default Unicode BiDi algorithm.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="STRUCTURED_TEXT_URI" value="1" enum="StructuredTextParser">
|
<constant name="STRUCTURED_TEXT_URI" value="1" enum="StructuredTextParser">
|
||||||
BiDi override for URI.
|
BiDi override for URI.
|
||||||
@ -1896,8 +1899,8 @@
|
|||||||
BiDi override for lists.
|
BiDi override for lists.
|
||||||
Structured text options: list separator [code]String[/code].
|
Structured text options: list separator [code]String[/code].
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="STRUCTURED_TEXT_NONE" value="5" enum="StructuredTextParser">
|
<constant name="STRUCTURED_TEXT_GDSCRIPT" value="5" enum="StructuredTextParser">
|
||||||
Use default Unicode BiDi algorithm.
|
BiDi override for GDScript.
|
||||||
</constant>
|
</constant>
|
||||||
<constant name="STRUCTURED_TEXT_CUSTOM" value="6" enum="StructuredTextParser">
|
<constant name="STRUCTURED_TEXT_CUSTOM" value="6" enum="StructuredTextParser">
|
||||||
User defined structured text BiDi override function.
|
User defined structured text BiDi override function.
|
||||||
|
@ -896,7 +896,7 @@
|
|||||||
</description>
|
</description>
|
||||||
</method>
|
</method>
|
||||||
<method name="_parse_structured_text" qualifiers="virtual const">
|
<method name="_parse_structured_text" qualifiers="virtual const">
|
||||||
<return type="Vector2i[]" />
|
<return type="Vector3i[]" />
|
||||||
<param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
|
<param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
|
||||||
<param index="1" name="args" type="Array" />
|
<param index="1" name="args" type="Array" />
|
||||||
<param index="2" name="text" type="String" />
|
<param index="2" name="text" type="String" />
|
||||||
|
@ -2086,6 +2086,7 @@ CodeTextEditor::CodeTextEditor() {
|
|||||||
text_editor = memnew(CodeEdit);
|
text_editor = memnew(CodeEdit);
|
||||||
add_child(text_editor);
|
add_child(text_editor);
|
||||||
text_editor->set_v_size_flags(SIZE_EXPAND_FILL);
|
text_editor->set_v_size_flags(SIZE_EXPAND_FILL);
|
||||||
|
text_editor->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_GDSCRIPT);
|
||||||
|
|
||||||
int ot_mode = EDITOR_GET("interface/editor/code_font_contextual_ligatures");
|
int ot_mode = EDITOR_GET("interface/editor/code_font_contextual_ligatures");
|
||||||
Ref<FontVariation> fc = text_editor->get_theme_font(SNAME("font"));
|
Ref<FontVariation> fc = text_editor->get_theme_font(SNAME("font"));
|
||||||
|
@ -3680,6 +3680,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
|
|||||||
|
|
||||||
RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
|
RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
|
||||||
_THREAD_SAFE_METHOD_
|
_THREAD_SAFE_METHOD_
|
||||||
|
ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");
|
||||||
|
|
||||||
ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);
|
ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);
|
||||||
sd->hb_buffer = hb_buffer_create();
|
sd->hb_buffer = hb_buffer_create();
|
||||||
@ -3705,6 +3706,7 @@ void TextServerAdvanced::_shaped_text_clear(const RID &p_shaped) {
|
|||||||
|
|
||||||
void TextServerAdvanced::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
|
void TextServerAdvanced::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
|
||||||
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
|
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
|
||||||
|
ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");
|
||||||
ERR_FAIL_COND(!sd);
|
ERR_FAIL_COND(!sd);
|
||||||
|
|
||||||
MutexLock lock(sd->mutex);
|
MutexLock lock(sd->mutex);
|
||||||
@ -3764,8 +3766,12 @@ void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, con
|
|||||||
}
|
}
|
||||||
sd->bidi_override.clear();
|
sd->bidi_override.clear();
|
||||||
for (int i = 0; i < p_override.size(); i++) {
|
for (int i = 0; i < p_override.size(); i++) {
|
||||||
if (p_override[i].get_type() == Variant::VECTOR2I) {
|
if (p_override[i].get_type() == Variant::VECTOR3I) {
|
||||||
sd->bidi_override.push_back(p_override[i]);
|
const Vector3i &r = p_override[i];
|
||||||
|
sd->bidi_override.push_back(r);
|
||||||
|
} else if (p_override[i].get_type() == Variant::VECTOR2I) {
|
||||||
|
const Vector2i &r = p_override[i];
|
||||||
|
sd->bidi_override.push_back(Vector3i(r.x, r.y, DIRECTION_INHERITED));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
invalidate(sd, false);
|
invalidate(sd, false);
|
||||||
@ -5570,8 +5576,31 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
|
|||||||
sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));
|
sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int base_para_direction = UBIDI_DEFAULT_LTR;
|
||||||
|
switch (sd->direction) {
|
||||||
|
case DIRECTION_LTR: {
|
||||||
|
sd->para_direction = DIRECTION_LTR;
|
||||||
|
base_para_direction = UBIDI_LTR;
|
||||||
|
} break;
|
||||||
|
case DIRECTION_RTL: {
|
||||||
|
sd->para_direction = DIRECTION_RTL;
|
||||||
|
base_para_direction = UBIDI_RTL;
|
||||||
|
} break;
|
||||||
|
case DIRECTION_INHERITED:
|
||||||
|
case DIRECTION_AUTO: {
|
||||||
|
UBiDiDirection direction = ubidi_getBaseDirection(data, sd->utf16.length());
|
||||||
|
if (direction != UBIDI_NEUTRAL) {
|
||||||
|
sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;
|
||||||
|
base_para_direction = direction;
|
||||||
|
} else {
|
||||||
|
sd->para_direction = DIRECTION_LTR;
|
||||||
|
base_para_direction = UBIDI_DEFAULT_LTR;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
|
||||||
if (sd->bidi_override.is_empty()) {
|
if (sd->bidi_override.is_empty()) {
|
||||||
sd->bidi_override.push_back(Vector2i(sd->start, sd->end));
|
sd->bidi_override.push_back(Vector3i(sd->start, sd->end, DIRECTION_INHERITED));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
|
for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
|
||||||
@ -5587,23 +5616,22 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
|
|||||||
UBiDi *bidi_iter = ubidi_openSized(end, 0, &err);
|
UBiDi *bidi_iter = ubidi_openSized(end, 0, &err);
|
||||||
ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
|
ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
|
||||||
|
|
||||||
switch (sd->direction) {
|
switch (static_cast<TextServer::Direction>(sd->bidi_override[ov].z)) {
|
||||||
case DIRECTION_LTR: {
|
case DIRECTION_LTR: {
|
||||||
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);
|
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);
|
||||||
sd->para_direction = DIRECTION_LTR;
|
|
||||||
} break;
|
} break;
|
||||||
case DIRECTION_RTL: {
|
case DIRECTION_RTL: {
|
||||||
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);
|
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);
|
||||||
sd->para_direction = DIRECTION_RTL;
|
} break;
|
||||||
|
case DIRECTION_INHERITED: {
|
||||||
|
ubidi_setPara(bidi_iter, data + start, end - start, base_para_direction, nullptr, &err);
|
||||||
} break;
|
} break;
|
||||||
case DIRECTION_AUTO: {
|
case DIRECTION_AUTO: {
|
||||||
UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);
|
UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);
|
||||||
if (direction != UBIDI_NEUTRAL) {
|
if (direction != UBIDI_NEUTRAL) {
|
||||||
ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
|
ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
|
||||||
sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;
|
|
||||||
} else {
|
} else {
|
||||||
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_DEFAULT_LTR, nullptr, &err);
|
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_DEFAULT_LTR, nullptr, &err);
|
||||||
sd->para_direction = DIRECTION_LTR;
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -500,7 +500,7 @@ class TextServerAdvanced : public TextServerExtension {
|
|||||||
/* Intermediate data */
|
/* Intermediate data */
|
||||||
Char16String utf16;
|
Char16String utf16;
|
||||||
Vector<UBiDi *> bidi_iter;
|
Vector<UBiDi *> bidi_iter;
|
||||||
Vector<Vector2i> bidi_override;
|
Vector<Vector3i> bidi_override;
|
||||||
ScriptIterator *script_iter = nullptr;
|
ScriptIterator *script_iter = nullptr;
|
||||||
hb_buffer_t *hb_buffer = nullptr;
|
hb_buffer_t *hb_buffer = nullptr;
|
||||||
|
|
||||||
|
@ -2683,6 +2683,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
|
|||||||
|
|
||||||
RID TextServerFallback::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
|
RID TextServerFallback::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
|
||||||
_THREAD_SAFE_METHOD_
|
_THREAD_SAFE_METHOD_
|
||||||
|
ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");
|
||||||
|
|
||||||
ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);
|
ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);
|
||||||
sd->direction = p_direction;
|
sd->direction = p_direction;
|
||||||
@ -2706,6 +2707,7 @@ void TextServerFallback::_shaped_text_clear(const RID &p_shaped) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TextServerFallback::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
|
void TextServerFallback::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
|
||||||
|
ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");
|
||||||
if (p_direction == DIRECTION_RTL) {
|
if (p_direction == DIRECTION_RTL) {
|
||||||
ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server.");
|
ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server.");
|
||||||
}
|
}
|
||||||
|
@ -442,7 +442,7 @@ void Label3D::_shape() {
|
|||||||
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
|
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedArray<Vector2i> stt;
|
TypedArray<Vector3i> stt;
|
||||||
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
|
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
|
||||||
GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt);
|
GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt);
|
||||||
} else {
|
} else {
|
||||||
|
@ -143,7 +143,7 @@ private:
|
|||||||
void _generate_glyph_surfaces(const Glyph &p_glyph, Vector2 &r_offset, const Color &p_modulate, int p_priority = 0, int p_outline_size = 0);
|
void _generate_glyph_surfaces(const Glyph &p_glyph, Vector2 &r_offset, const Color &p_modulate, int p_priority = 0, int p_outline_size = 0);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
GDVIRTUAL2RC(Array, _structured_text_parser, Array, String)
|
GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String)
|
||||||
|
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
|
||||||
|
@ -2769,9 +2769,9 @@ void Control::end_bulk_theme_override() {
|
|||||||
|
|
||||||
// Internationalization.
|
// Internationalization.
|
||||||
|
|
||||||
TypedArray<Vector2i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
|
TypedArray<Vector3i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
|
||||||
if (p_parser_type == TextServer::STRUCTURED_TEXT_CUSTOM) {
|
if (p_parser_type == TextServer::STRUCTURED_TEXT_CUSTOM) {
|
||||||
TypedArray<Vector2i> ret;
|
TypedArray<Vector3i> ret;
|
||||||
GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret);
|
GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret);
|
||||||
return ret;
|
return ret;
|
||||||
} else {
|
} else {
|
||||||
|
@ -145,7 +145,7 @@ public:
|
|||||||
TEXT_DIRECTION_AUTO = TextServer::DIRECTION_AUTO,
|
TEXT_DIRECTION_AUTO = TextServer::DIRECTION_AUTO,
|
||||||
TEXT_DIRECTION_LTR = TextServer::DIRECTION_LTR,
|
TEXT_DIRECTION_LTR = TextServer::DIRECTION_LTR,
|
||||||
TEXT_DIRECTION_RTL = TextServer::DIRECTION_RTL,
|
TEXT_DIRECTION_RTL = TextServer::DIRECTION_RTL,
|
||||||
TEXT_DIRECTION_INHERITED,
|
TEXT_DIRECTION_INHERITED = TextServer::DIRECTION_INHERITED,
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -330,7 +330,7 @@ protected:
|
|||||||
|
|
||||||
// Internationalization.
|
// Internationalization.
|
||||||
|
|
||||||
virtual TypedArray<Vector2i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
|
virtual TypedArray<Vector3i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
|
||||||
|
|
||||||
// Base object overrides.
|
// Base object overrides.
|
||||||
|
|
||||||
@ -340,7 +340,7 @@ protected:
|
|||||||
// Exposed virtual methods.
|
// Exposed virtual methods.
|
||||||
|
|
||||||
GDVIRTUAL1RC(bool, _has_point, Vector2)
|
GDVIRTUAL1RC(bool, _has_point, Vector2)
|
||||||
GDVIRTUAL2RC(TypedArray<Vector2i>, _structured_text_parser, Array, String)
|
GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String)
|
||||||
GDVIRTUAL0RC(Vector2, _get_minimum_size)
|
GDVIRTUAL0RC(Vector2, _get_minimum_size)
|
||||||
|
|
||||||
GDVIRTUAL1RC(Variant, _get_drag_data, Vector2)
|
GDVIRTUAL1RC(Variant, _get_drag_data, Vector2)
|
||||||
|
@ -4074,8 +4074,8 @@ void RichTextLabel::append_text(const String &p_bbcode) {
|
|||||||
st_parser_type = TextServer::STRUCTURED_TEXT_EMAIL;
|
st_parser_type = TextServer::STRUCTURED_TEXT_EMAIL;
|
||||||
} else if (subtag_a[1] == "l" || subtag_a[1] == "list") {
|
} else if (subtag_a[1] == "l" || subtag_a[1] == "list") {
|
||||||
st_parser_type = TextServer::STRUCTURED_TEXT_LIST;
|
st_parser_type = TextServer::STRUCTURED_TEXT_LIST;
|
||||||
} else if (subtag_a[1] == "n" || subtag_a[1] == "none") {
|
} else if (subtag_a[1] == "n" || subtag_a[1] == "gdscript") {
|
||||||
st_parser_type = TextServer::STRUCTURED_TEXT_NONE;
|
st_parser_type = TextServer::STRUCTURED_TEXT_GDSCRIPT;
|
||||||
} else if (subtag_a[1] == "c" || subtag_a[1] == "custom") {
|
} else if (subtag_a[1] == "c" || subtag_a[1] == "custom") {
|
||||||
st_parser_type = TextServer::STRUCTURED_TEXT_CUSTOM;
|
st_parser_type = TextServer::STRUCTURED_TEXT_CUSTOM;
|
||||||
}
|
}
|
||||||
|
@ -1208,7 +1208,15 @@ void TextEdit::_notification(int p_what) {
|
|||||||
char_ofs = 0;
|
char_ofs = 0;
|
||||||
}
|
}
|
||||||
for (int j = 0; j < gl_size; j++) {
|
for (int j = 0; j < gl_size; j++) {
|
||||||
const Variant *color_data = color_map.getptr(glyphs[j].start);
|
int64_t color_start = -1;
|
||||||
|
for (const Variant *key = color_map.next(nullptr); key; key = color_map.next(key)) {
|
||||||
|
if (int64_t(*key) <= glyphs[j].start) {
|
||||||
|
color_start = *key;
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const Variant *color_data = (color_start >= 0) ? color_map.getptr(color_start) : nullptr;
|
||||||
if (color_data != nullptr) {
|
if (color_data != nullptr) {
|
||||||
current_color = (color_data->operator Dictionary()).get("color", font_color);
|
current_color = (color_data->operator Dictionary()).get("color", font_color);
|
||||||
if (!editable && current_color.a > font_readonly_color.a) {
|
if (!editable && current_color.a > font_readonly_color.a) {
|
||||||
|
@ -332,7 +332,7 @@ void TreeItem::set_structured_text_bidi_override(int p_column, TextServer::Struc
|
|||||||
}
|
}
|
||||||
|
|
||||||
TextServer::StructuredTextParser TreeItem::get_structured_text_bidi_override(int p_column) const {
|
TextServer::StructuredTextParser TreeItem::get_structured_text_bidi_override(int p_column) const {
|
||||||
ERR_FAIL_INDEX_V(p_column, cells.size(), TextServer::STRUCTURED_TEXT_NONE);
|
ERR_FAIL_INDEX_V(p_column, cells.size(), TextServer::STRUCTURED_TEXT_DEFAULT);
|
||||||
return cells[p_column].st_parser;
|
return cells[p_column].st_parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2901,7 +2901,7 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
|
|||||||
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
|
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
|
||||||
}
|
}
|
||||||
|
|
||||||
Array stt;
|
TypedArray<Vector3i> stt;
|
||||||
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
|
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
|
||||||
GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt);
|
GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt);
|
||||||
} else {
|
} else {
|
||||||
|
@ -622,7 +622,7 @@ protected:
|
|||||||
virtual void _create_mesh_array(Array &p_arr) const override;
|
virtual void _create_mesh_array(Array &p_arr) const override;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GDVIRTUAL2RC(Array, _structured_text_parser, Array, String)
|
GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String)
|
||||||
|
|
||||||
TextMesh();
|
TextMesh();
|
||||||
~TextMesh();
|
~TextMesh();
|
||||||
|
@ -1373,8 +1373,8 @@ String TextServerExtension::string_to_lower(const String &p_string, const String
|
|||||||
return p_string;
|
return p_string;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedArray<Vector2i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
|
TypedArray<Vector3i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
|
||||||
TypedArray<Vector2i> ret;
|
TypedArray<Vector3i> ret;
|
||||||
GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret);
|
GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -521,8 +521,8 @@ public:
|
|||||||
GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &);
|
GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &);
|
||||||
GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &);
|
GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &);
|
||||||
|
|
||||||
TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
|
TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
|
||||||
GDVIRTUAL3RC(TypedArray<Vector2i>, _parse_structured_text, StructuredTextParser, const Array &, const String &);
|
GDVIRTUAL3RC(TypedArray<Vector3i>, _parse_structured_text, StructuredTextParser, const Array &, const String &);
|
||||||
|
|
||||||
virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
|
virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
|
||||||
virtual bool spoof_check(const String &p_string) const override;
|
virtual bool spoof_check(const String &p_string) const override;
|
||||||
|
@ -483,6 +483,7 @@ void TextServer::_bind_methods() {
|
|||||||
BIND_ENUM_CONSTANT(DIRECTION_AUTO);
|
BIND_ENUM_CONSTANT(DIRECTION_AUTO);
|
||||||
BIND_ENUM_CONSTANT(DIRECTION_LTR);
|
BIND_ENUM_CONSTANT(DIRECTION_LTR);
|
||||||
BIND_ENUM_CONSTANT(DIRECTION_RTL);
|
BIND_ENUM_CONSTANT(DIRECTION_RTL);
|
||||||
|
BIND_ENUM_CONSTANT(DIRECTION_INHERITED);
|
||||||
|
|
||||||
/* Orientation */
|
/* Orientation */
|
||||||
BIND_ENUM_CONSTANT(ORIENTATION_HORIZONTAL);
|
BIND_ENUM_CONSTANT(ORIENTATION_HORIZONTAL);
|
||||||
@ -599,7 +600,7 @@ void TextServer::_bind_methods() {
|
|||||||
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_FILE);
|
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_FILE);
|
||||||
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_EMAIL);
|
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_EMAIL);
|
||||||
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_LIST);
|
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_LIST);
|
||||||
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_NONE);
|
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_GDSCRIPT);
|
||||||
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_CUSTOM);
|
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_CUSTOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1692,22 +1693,22 @@ String TextServer::strip_diacritics(const String &p_string) const {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
|
TypedArray<Vector3i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
|
||||||
TypedArray<Vector2i> ret;
|
TypedArray<Vector3i> ret;
|
||||||
switch (p_parser_type) {
|
switch (p_parser_type) {
|
||||||
case STRUCTURED_TEXT_URI: {
|
case STRUCTURED_TEXT_URI: {
|
||||||
int prev = 0;
|
int prev = 0;
|
||||||
for (int i = 0; i < p_text.length(); i++) {
|
for (int i = 0; i < p_text.length(); i++) {
|
||||||
if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == '.') || (p_text[i] == ':') || (p_text[i] == '&') || (p_text[i] == '=') || (p_text[i] == '@') || (p_text[i] == '?') || (p_text[i] == '#')) {
|
if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == '.') || (p_text[i] == ':') || (p_text[i] == '&') || (p_text[i] == '=') || (p_text[i] == '@') || (p_text[i] == '?') || (p_text[i] == '#')) {
|
||||||
if (prev != i) {
|
if (prev != i) {
|
||||||
ret.push_back(Vector2i(prev, i));
|
ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
|
||||||
}
|
}
|
||||||
ret.push_back(Vector2i(i, i + 1));
|
ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
|
||||||
prev = i + 1;
|
prev = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prev != p_text.length()) {
|
if (prev != p_text.length()) {
|
||||||
ret.push_back(Vector2i(prev, p_text.length()));
|
ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case STRUCTURED_TEXT_FILE: {
|
case STRUCTURED_TEXT_FILE: {
|
||||||
@ -1715,14 +1716,14 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa
|
|||||||
for (int i = 0; i < p_text.length(); i++) {
|
for (int i = 0; i < p_text.length(); i++) {
|
||||||
if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == ':')) {
|
if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == ':')) {
|
||||||
if (prev != i) {
|
if (prev != i) {
|
||||||
ret.push_back(Vector2i(prev, i));
|
ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
|
||||||
}
|
}
|
||||||
ret.push_back(Vector2i(i, i + 1));
|
ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
|
||||||
prev = i + 1;
|
prev = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prev != p_text.length()) {
|
if (prev != p_text.length()) {
|
||||||
ret.push_back(Vector2i(prev, p_text.length()));
|
ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case STRUCTURED_TEXT_EMAIL: {
|
case STRUCTURED_TEXT_EMAIL: {
|
||||||
@ -1731,19 +1732,19 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa
|
|||||||
for (int i = 0; i < p_text.length(); i++) {
|
for (int i = 0; i < p_text.length(); i++) {
|
||||||
if ((p_text[i] == '@') && local) { // Add full "local" as single context.
|
if ((p_text[i] == '@') && local) { // Add full "local" as single context.
|
||||||
local = false;
|
local = false;
|
||||||
ret.push_back(Vector2i(prev, i));
|
ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
|
||||||
ret.push_back(Vector2i(i, i + 1));
|
ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
|
||||||
prev = i + 1;
|
prev = i + 1;
|
||||||
} else if (!local && (p_text[i] == '.')) { // Add each dot separated "domain" part as context.
|
} else if (!local && (p_text[i] == '.')) { // Add each dot separated "domain" part as context.
|
||||||
if (prev != i) {
|
if (prev != i) {
|
||||||
ret.push_back(Vector2i(prev, i));
|
ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
|
||||||
}
|
}
|
||||||
ret.push_back(Vector2i(i, i + 1));
|
ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
|
||||||
prev = i + 1;
|
prev = i + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prev != p_text.length()) {
|
if (prev != p_text.length()) {
|
||||||
ret.push_back(Vector2i(prev, p_text.length()));
|
ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case STRUCTURED_TEXT_LIST: {
|
case STRUCTURED_TEXT_LIST: {
|
||||||
@ -1752,18 +1753,97 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa
|
|||||||
int prev = 0;
|
int prev = 0;
|
||||||
for (int i = 0; i < tags.size(); i++) {
|
for (int i = 0; i < tags.size(); i++) {
|
||||||
if (prev != i) {
|
if (prev != i) {
|
||||||
ret.push_back(Vector2i(prev, prev + tags[i].length()));
|
ret.push_back(Vector3i(prev, prev + tags[i].length(), TextServer::DIRECTION_INHERITED));
|
||||||
}
|
}
|
||||||
ret.push_back(Vector2i(prev + tags[i].length(), prev + tags[i].length() + 1));
|
ret.push_back(Vector3i(prev + tags[i].length(), prev + tags[i].length() + 1, TextServer::DIRECTION_INHERITED));
|
||||||
prev = prev + tags[i].length() + 1;
|
prev = prev + tags[i].length() + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
case STRUCTURED_TEXT_GDSCRIPT: {
|
||||||
|
bool in_string_literal = false;
|
||||||
|
bool in_string_literal_single = false;
|
||||||
|
bool in_id = false;
|
||||||
|
|
||||||
|
int prev = 0;
|
||||||
|
for (int i = 0; i < p_text.length(); i++) {
|
||||||
|
char32_t c = p_text[i];
|
||||||
|
if (in_string_literal) {
|
||||||
|
if (c == '\\') {
|
||||||
|
i++;
|
||||||
|
continue; // Skip escaped chars.
|
||||||
|
} else if (c == '\"') {
|
||||||
|
// String literal end, push string and ".
|
||||||
|
if (prev != i) {
|
||||||
|
ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
|
||||||
|
}
|
||||||
|
prev = i + 1;
|
||||||
|
ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
|
||||||
|
in_string_literal = false;
|
||||||
|
}
|
||||||
|
} else if (in_string_literal_single) {
|
||||||
|
if (c == '\\') {
|
||||||
|
i++;
|
||||||
|
continue; // Skip escaped chars.
|
||||||
|
} else if (c == '\'') {
|
||||||
|
// String literal end, push string and '.
|
||||||
|
if (prev != i) {
|
||||||
|
ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
|
||||||
|
}
|
||||||
|
prev = i + 1;
|
||||||
|
ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
|
||||||
|
in_string_literal_single = false;
|
||||||
|
}
|
||||||
|
} else if (in_id) {
|
||||||
|
if (!is_unicode_identifier_continue(c)) {
|
||||||
|
// End of id, push id.
|
||||||
|
if (prev != i) {
|
||||||
|
ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
|
||||||
|
}
|
||||||
|
prev = i;
|
||||||
|
in_id = false;
|
||||||
|
}
|
||||||
|
} else if (is_unicode_identifier_start(c)) {
|
||||||
|
// Start of new id, push prev element.
|
||||||
|
if (prev != i) {
|
||||||
|
ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
|
||||||
|
}
|
||||||
|
prev = i;
|
||||||
|
in_id = true;
|
||||||
|
} else if (c == '\"') {
|
||||||
|
// String literal start, push prev element and ".
|
||||||
|
if (prev != i) {
|
||||||
|
ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
|
||||||
|
}
|
||||||
|
prev = i + 1;
|
||||||
|
ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
|
||||||
|
in_string_literal = true;
|
||||||
|
} else if (c == '\'') {
|
||||||
|
// String literal start, push prev element and '.
|
||||||
|
if (prev != i) {
|
||||||
|
ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
|
||||||
|
}
|
||||||
|
prev = i + 1;
|
||||||
|
ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
|
||||||
|
in_string_literal_single = true;
|
||||||
|
} else if (c == '#') {
|
||||||
|
// Start of comment, push prev element and #, skip the rest of the text.
|
||||||
|
if (prev != i) {
|
||||||
|
ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
|
||||||
|
}
|
||||||
|
prev = i + 1;
|
||||||
|
ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (prev < p_text.length()) {
|
||||||
|
ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
|
||||||
|
}
|
||||||
|
} break;
|
||||||
case STRUCTURED_TEXT_CUSTOM:
|
case STRUCTURED_TEXT_CUSTOM:
|
||||||
case STRUCTURED_TEXT_NONE:
|
|
||||||
case STRUCTURED_TEXT_DEFAULT:
|
case STRUCTURED_TEXT_DEFAULT:
|
||||||
default: {
|
default: {
|
||||||
ret.push_back(Vector2i(0, p_text.length()));
|
ret.push_back(Vector3i(0, p_text.length(), TextServer::DIRECTION_INHERITED));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -65,7 +65,8 @@ public:
|
|||||||
enum Direction {
|
enum Direction {
|
||||||
DIRECTION_AUTO,
|
DIRECTION_AUTO,
|
||||||
DIRECTION_LTR,
|
DIRECTION_LTR,
|
||||||
DIRECTION_RTL
|
DIRECTION_RTL,
|
||||||
|
DIRECTION_INHERITED,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Orientation {
|
enum Orientation {
|
||||||
@ -198,7 +199,7 @@ public:
|
|||||||
STRUCTURED_TEXT_FILE,
|
STRUCTURED_TEXT_FILE,
|
||||||
STRUCTURED_TEXT_EMAIL,
|
STRUCTURED_TEXT_EMAIL,
|
||||||
STRUCTURED_TEXT_LIST,
|
STRUCTURED_TEXT_LIST,
|
||||||
STRUCTURED_TEXT_NONE,
|
STRUCTURED_TEXT_GDSCRIPT,
|
||||||
STRUCTURED_TEXT_CUSTOM
|
STRUCTURED_TEXT_CUSTOM
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -505,7 +506,7 @@ public:
|
|||||||
virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0;
|
virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0;
|
||||||
virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0;
|
virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0;
|
||||||
|
|
||||||
TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
|
TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
|
||||||
|
|
||||||
virtual void cleanup() {}
|
virtual void cleanup() {}
|
||||||
|
|
||||||
|
@ -734,7 +734,7 @@ TEST_CASE("[SceneTree][Primitive][Text] Text Primitive") {
|
|||||||
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_FILE ||
|
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_FILE ||
|
||||||
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_EMAIL ||
|
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_EMAIL ||
|
||||||
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_LIST ||
|
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_LIST ||
|
||||||
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_NONE ||
|
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_GDSCRIPT ||
|
||||||
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_CUSTOM));
|
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_CUSTOM));
|
||||||
CHECK(text->get_structured_text_bidi_override_options().size() >= 0);
|
CHECK(text->get_structured_text_bidi_override_options().size() >= 0);
|
||||||
CHECK(text->get_width() > 0);
|
CHECK(text->get_width() > 0);
|
||||||
|
Loading…
Reference in New Issue
Block a user