2020-09-03 13:22:16 +02:00
/**************************************************************************/
/* text_paragraph.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
# include "scene/resources/text_paragraph.h"
void TextParagraph : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " clear " ) , & TextParagraph : : clear ) ;
ClassDB : : bind_method ( D_METHOD ( " set_direction " , " direction " ) , & TextParagraph : : set_direction ) ;
ClassDB : : bind_method ( D_METHOD ( " get_direction " ) , & TextParagraph : : get_direction ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " direction " , PROPERTY_HINT_ENUM , " Auto,Light-to-right,Right-to-left " ) , " set_direction " , " get_direction " ) ;
2021-03-06 10:52:16 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_custom_punctuation " , " custom_punctuation " ) , & TextParagraph : : set_custom_punctuation ) ;
ClassDB : : bind_method ( D_METHOD ( " get_custom_punctuation " ) , & TextParagraph : : get_custom_punctuation ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " custom_punctuation " ) , " set_custom_punctuation " , " get_custom_punctuation " ) ;
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_orientation " , " orientation " ) , & TextParagraph : : set_orientation ) ;
ClassDB : : bind_method ( D_METHOD ( " get_orientation " ) , & TextParagraph : : get_orientation ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " orientation " , PROPERTY_HINT_ENUM , " Horizontal,Orientation " ) , " set_orientation " , " get_orientation " ) ;
ClassDB : : bind_method ( D_METHOD ( " set_preserve_invalid " , " enabled " ) , & TextParagraph : : set_preserve_invalid ) ;
ClassDB : : bind_method ( D_METHOD ( " get_preserve_invalid " ) , & TextParagraph : : get_preserve_invalid ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " preserve_invalid " ) , " set_preserve_invalid " , " get_preserve_invalid " ) ;
ClassDB : : bind_method ( D_METHOD ( " set_preserve_control " , " enabled " ) , & TextParagraph : : set_preserve_control ) ;
ClassDB : : bind_method ( D_METHOD ( " get_preserve_control " ) , & TextParagraph : : get_preserve_control ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " preserve_control " ) , " set_preserve_control " , " get_preserve_control " ) ;
2021-08-27 23:19:51 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_bidi_override " , " override " ) , & TextParagraph : : set_bidi_override ) ;
2020-09-03 13:22:16 +02:00
2022-05-09 11:47:10 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_dropcap " , " text " , " font " , " font_size " , " dropcap_margins " , " language " ) , & TextParagraph : : set_dropcap , DEFVAL ( Rect2 ( ) ) , DEFVAL ( " " ) ) ;
2020-11-19 15:45:23 +01:00
ClassDB : : bind_method ( D_METHOD ( " clear_dropcap " ) , & TextParagraph : : clear_dropcap ) ;
2022-05-09 11:47:10 +02:00
ClassDB : : bind_method ( D_METHOD ( " add_string " , " text " , " font " , " font_size " , " language " , " meta " ) , & TextParagraph : : add_string , DEFVAL ( " " ) , DEFVAL ( Variant ( ) ) ) ;
2022-12-08 21:01:07 +01:00
ClassDB : : bind_method ( D_METHOD ( " add_object " , " key " , " size " , " inline_align " , " length " , " baseline " ) , & TextParagraph : : add_object , DEFVAL ( INLINE_ALIGNMENT_CENTER ) , DEFVAL ( 1 ) , DEFVAL ( 0.0 ) ) ;
ClassDB : : bind_method ( D_METHOD ( " resize_object " , " key " , " size " , " inline_align " , " baseline " ) , & TextParagraph : : resize_object , DEFVAL ( INLINE_ALIGNMENT_CENTER ) , DEFVAL ( 0.0 ) ) ;
2020-09-03 13:22:16 +02:00
2021-11-25 03:58:47 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_alignment " , " alignment " ) , & TextParagraph : : set_alignment ) ;
ClassDB : : bind_method ( D_METHOD ( " get_alignment " ) , & TextParagraph : : get_alignment ) ;
2020-09-03 13:22:16 +02:00
2021-11-25 03:58:47 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " alignment " , PROPERTY_HINT_ENUM , " Left,Center,Right,Fill " ) , " set_alignment " , " get_alignment " ) ;
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " tab_align " , " tab_stops " ) , & TextParagraph : : tab_align ) ;
2022-07-11 11:40:31 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_break_flags " , " flags " ) , & TextParagraph : : set_break_flags ) ;
ClassDB : : bind_method ( D_METHOD ( " get_break_flags " ) , & TextParagraph : : get_break_flags ) ;
2020-09-03 13:22:16 +02:00
2022-08-30 10:56:17 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " break_flags " , PROPERTY_HINT_FLAGS , " Mandatory,Word Bound,Grapheme Bound,Adaptive,Trim Spaces " ) , " set_break_flags " , " get_break_flags " ) ;
2022-07-11 11:40:31 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_justification_flags " , " flags " ) , & TextParagraph : : set_justification_flags ) ;
ClassDB : : bind_method ( D_METHOD ( " get_justification_flags " ) , & TextParagraph : : get_justification_flags ) ;
2023-03-23 10:22:37 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " justification_flags " , PROPERTY_HINT_FLAGS , " Kashida Justification:1,Word Justification:2,Trim Edge Spaces After Justification:4,Justify Only After Last Tab:8,Constrain Ellipsis:16,Skip Last Line:32,Skip Last Line With Visible Characters:64,Do Not Skip Single Line:128 " ) , " set_justification_flags " , " get_justification_flags " ) ;
2020-09-03 13:22:16 +02:00
2021-08-11 00:09:48 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_text_overrun_behavior " , " overrun_behavior " ) , & TextParagraph : : set_text_overrun_behavior ) ;
ClassDB : : bind_method ( D_METHOD ( " get_text_overrun_behavior " ) , & TextParagraph : : get_text_overrun_behavior ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " text_overrun_behavior " , PROPERTY_HINT_ENUM , " Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis " ) , " set_text_overrun_behavior " , " get_text_overrun_behavior " ) ;
2023-10-01 12:39:13 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_ellipsis_char " , " char " ) , & TextParagraph : : set_ellipsis_char ) ;
ClassDB : : bind_method ( D_METHOD ( " get_ellipsis_char " ) , & TextParagraph : : get_ellipsis_char ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " ellipsis_char " ) , " set_ellipsis_char " , " get_ellipsis_char " ) ;
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_width " , " width " ) , & TextParagraph : : set_width ) ;
ClassDB : : bind_method ( D_METHOD ( " get_width " ) , & TextParagraph : : get_width ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : FLOAT , " width " ) , " set_width " , " get_width " ) ;
2021-10-19 21:38:58 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_non_wrapped_size " ) , & TextParagraph : : get_non_wrapped_size ) ;
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_size " ) , & TextParagraph : : get_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_rid " ) , & TextParagraph : : get_rid ) ;
ClassDB : : bind_method ( D_METHOD ( " get_line_rid " , " line " ) , & TextParagraph : : get_line_rid ) ;
2020-11-19 15:45:23 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_dropcap_rid " ) , & TextParagraph : : get_dropcap_rid ) ;
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_line_count " ) , & TextParagraph : : get_line_count ) ;
2021-08-11 00:09:48 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_max_lines_visible " , " max_lines_visible " ) , & TextParagraph : : set_max_lines_visible ) ;
ClassDB : : bind_method ( D_METHOD ( " get_max_lines_visible " ) , & TextParagraph : : get_max_lines_visible ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " max_lines_visible " ) , " set_max_lines_visible " , " get_max_lines_visible " ) ;
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_line_objects " , " line " ) , & TextParagraph : : get_line_objects ) ;
ClassDB : : bind_method ( D_METHOD ( " get_line_object_rect " , " line " , " key " ) , & TextParagraph : : get_line_object_rect ) ;
ClassDB : : bind_method ( D_METHOD ( " get_line_size " , " line " ) , & TextParagraph : : get_line_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_line_range " , " line " ) , & TextParagraph : : get_line_range ) ;
ClassDB : : bind_method ( D_METHOD ( " get_line_ascent " , " line " ) , & TextParagraph : : get_line_ascent ) ;
ClassDB : : bind_method ( D_METHOD ( " get_line_descent " , " line " ) , & TextParagraph : : get_line_descent ) ;
ClassDB : : bind_method ( D_METHOD ( " get_line_width " , " line " ) , & TextParagraph : : get_line_width ) ;
ClassDB : : bind_method ( D_METHOD ( " get_line_underline_position " , " line " ) , & TextParagraph : : get_line_underline_position ) ;
ClassDB : : bind_method ( D_METHOD ( " get_line_underline_thickness " , " line " ) , & TextParagraph : : get_line_underline_thickness ) ;
2020-11-19 15:45:23 +01:00
ClassDB : : bind_method ( D_METHOD ( " get_dropcap_size " ) , & TextParagraph : : get_dropcap_size ) ;
ClassDB : : bind_method ( D_METHOD ( " get_dropcap_lines " ) , & TextParagraph : : get_dropcap_lines ) ;
ClassDB : : bind_method ( D_METHOD ( " draw " , " canvas " , " pos " , " color " , " dc_color " ) , & TextParagraph : : draw , DEFVAL ( Color ( 1 , 1 , 1 ) ) , DEFVAL ( Color ( 1 , 1 , 1 ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " draw_outline " , " canvas " , " pos " , " outline_size " , " color " , " dc_color " ) , & TextParagraph : : draw_outline , DEFVAL ( 1 ) , DEFVAL ( Color ( 1 , 1 , 1 ) ) , DEFVAL ( Color ( 1 , 1 , 1 ) ) ) ;
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " draw_line " , " canvas " , " pos " , " line " , " color " ) , & TextParagraph : : draw_line , DEFVAL ( Color ( 1 , 1 , 1 ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " draw_line_outline " , " canvas " , " pos " , " line " , " outline_size " , " color " ) , & TextParagraph : : draw_line_outline , DEFVAL ( 1 ) , DEFVAL ( Color ( 1 , 1 , 1 ) ) ) ;
2020-11-19 15:45:23 +01:00
ClassDB : : bind_method ( D_METHOD ( " draw_dropcap " , " canvas " , " pos " , " color " ) , & TextParagraph : : draw_dropcap , DEFVAL ( Color ( 1 , 1 , 1 ) ) ) ;
ClassDB : : bind_method ( D_METHOD ( " draw_dropcap_outline " , " canvas " , " pos " , " outline_size " , " color " ) , & TextParagraph : : draw_dropcap_outline , DEFVAL ( 1 ) , DEFVAL ( Color ( 1 , 1 , 1 ) ) ) ;
2020-09-03 13:22:16 +02:00
ClassDB : : bind_method ( D_METHOD ( " hit_test " , " coords " ) , & TextParagraph : : hit_test ) ;
}
void TextParagraph : : _shape_lines ( ) {
2023-01-28 03:31:44 +01:00
// When a shaped text is invalidated by an external source, we want to reshape it.
if ( ! TS - > shaped_text_is_ready ( rid ) | | ! TS - > shaped_text_is_ready ( dropcap_rid ) ) {
lines_dirty = true ;
}
for ( const RID & line_rid : lines_rid ) {
if ( ! TS - > shaped_text_is_ready ( line_rid ) ) {
lines_dirty = true ;
break ;
}
}
2021-08-11 00:09:48 +02:00
if ( lines_dirty ) {
2022-12-29 01:24:45 +01:00
for ( const RID & line_rid : lines_rid ) {
TS - > free_rid ( line_rid ) ;
2020-09-03 13:22:16 +02:00
}
2021-08-11 00:09:48 +02:00
lines_rid . clear ( ) ;
2020-09-03 13:22:16 +02:00
2020-12-15 13:04:21 +01:00
if ( ! tab_stops . is_empty ( ) ) {
2020-09-03 13:22:16 +02:00
TS - > shaped_text_tab_align ( rid , tab_stops ) ;
}
2020-11-19 15:45:23 +01:00
float h_offset = 0.f ;
float v_offset = 0.f ;
int start = 0 ;
dropcap_lines = 0 ;
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . x + dropcap_margins . size . x + dropcap_margins . position . x ;
v_offset = TS - > shaped_text_get_size ( dropcap_rid ) . y + dropcap_margins . size . y + dropcap_margins . position . y ;
} else {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . y + dropcap_margins . size . y + dropcap_margins . position . y ;
v_offset = TS - > shaped_text_get_size ( dropcap_rid ) . x + dropcap_margins . size . x + dropcap_margins . position . x ;
}
2024-08-29 08:37:23 +02:00
Size2i range = TS - > shaped_text_get_range ( rid ) ;
2020-11-19 15:45:23 +01:00
if ( h_offset > 0 ) {
// Dropcap, flow around.
2022-07-11 11:40:31 +02:00
PackedInt32Array line_breaks = TS - > shaped_text_get_line_breaks ( rid , width - h_offset , 0 , brk_flags ) ;
2021-08-27 23:19:51 +02:00
for ( int i = 0 ; i < line_breaks . size ( ) ; i = i + 2 ) {
RID line = TS - > shaped_text_substr ( rid , line_breaks [ i ] , line_breaks [ i + 1 ] - line_breaks [ i ] ) ;
2020-11-19 15:45:23 +01:00
float h = ( TS - > shaped_text_get_orientation ( line ) = = TextServer : : ORIENTATION_HORIZONTAL ) ? TS - > shaped_text_get_size ( line ) . y : TS - > shaped_text_get_size ( line ) . x ;
2020-12-29 09:54:59 +01:00
if ( ! tab_stops . is_empty ( ) ) {
2020-11-19 15:45:23 +01:00
TS - > shaped_text_tab_align ( line , tab_stops ) ;
}
2024-08-29 08:37:23 +02:00
start = ( i < line_breaks . size ( ) - 2 ) ? line_breaks [ i + 2 ] : range . y ;
2021-08-11 00:09:48 +02:00
lines_rid . push_back ( line ) ;
2023-10-31 08:34:43 +01:00
if ( v_offset < h ) {
break ;
}
dropcap_lines + + ;
v_offset - = h ;
2020-11-19 15:45:23 +01:00
}
}
// Use fixed for the rest of lines.
2024-08-29 08:37:23 +02:00
if ( start = = 0 | | start < range . y ) {
PackedInt32Array line_breaks = TS - > shaped_text_get_line_breaks ( rid , width , start , brk_flags ) ;
for ( int i = 0 ; i < line_breaks . size ( ) ; i = i + 2 ) {
RID line = TS - > shaped_text_substr ( rid , line_breaks [ i ] , line_breaks [ i + 1 ] - line_breaks [ i ] ) ;
if ( ! tab_stops . is_empty ( ) ) {
TS - > shaped_text_tab_align ( line , tab_stops ) ;
}
lines_rid . push_back ( line ) ;
2020-09-03 13:22:16 +02:00
}
2021-08-11 00:09:48 +02:00
}
2022-07-11 11:40:31 +02:00
BitField < TextServer : : TextOverrunFlag > overrun_flags = TextServer : : OVERRUN_NO_TRIM ;
2022-06-15 10:01:45 +02:00
if ( overrun_behavior ! = TextServer : : OVERRUN_NO_TRIMMING ) {
2021-08-11 00:09:48 +02:00
switch ( overrun_behavior ) {
2022-06-15 10:01:45 +02:00
case TextServer : : OVERRUN_TRIM_WORD_ELLIPSIS :
2022-07-11 11:40:31 +02:00
overrun_flags . set_flag ( TextServer : : OVERRUN_TRIM ) ;
overrun_flags . set_flag ( TextServer : : OVERRUN_TRIM_WORD_ONLY ) ;
overrun_flags . set_flag ( TextServer : : OVERRUN_ADD_ELLIPSIS ) ;
2021-08-11 00:09:48 +02:00
break ;
2022-06-15 10:01:45 +02:00
case TextServer : : OVERRUN_TRIM_ELLIPSIS :
2022-07-11 11:40:31 +02:00
overrun_flags . set_flag ( TextServer : : OVERRUN_TRIM ) ;
overrun_flags . set_flag ( TextServer : : OVERRUN_ADD_ELLIPSIS ) ;
2021-08-11 00:09:48 +02:00
break ;
2022-06-15 10:01:45 +02:00
case TextServer : : OVERRUN_TRIM_WORD :
2022-07-11 11:40:31 +02:00
overrun_flags . set_flag ( TextServer : : OVERRUN_TRIM ) ;
overrun_flags . set_flag ( TextServer : : OVERRUN_TRIM_WORD_ONLY ) ;
2021-08-11 00:09:48 +02:00
break ;
2022-06-15 10:01:45 +02:00
case TextServer : : OVERRUN_TRIM_CHAR :
2022-07-11 11:40:31 +02:00
overrun_flags . set_flag ( TextServer : : OVERRUN_TRIM ) ;
2021-08-11 00:09:48 +02:00
break ;
2022-06-15 10:01:45 +02:00
case TextServer : : OVERRUN_NO_TRIMMING :
2021-08-11 00:09:48 +02:00
break ;
}
}
2022-07-11 11:40:31 +02:00
bool autowrap_enabled = brk_flags . has_flag ( TextServer : : BREAK_WORD_BOUND ) | | brk_flags . has_flag ( TextServer : : BREAK_GRAPHEME_BOUND ) ;
2021-08-11 00:09:48 +02:00
// Fill after min_size calculation.
if ( autowrap_enabled ) {
2022-05-18 09:17:55 +02:00
int visible_lines = ( max_lines_visible > = 0 ) ? MIN ( max_lines_visible , ( int ) lines_rid . size ( ) ) : ( int ) lines_rid . size ( ) ;
bool lines_hidden = visible_lines > 0 & & visible_lines < ( int ) lines_rid . size ( ) ;
2021-08-11 00:09:48 +02:00
if ( lines_hidden ) {
2022-07-11 11:40:31 +02:00
overrun_flags . set_flag ( TextServer : : OVERRUN_ENFORCE_ELLIPSIS ) ;
2021-08-11 00:09:48 +02:00
}
2021-11-25 03:58:47 +01:00
if ( alignment = = HORIZONTAL_ALIGNMENT_FILL ) {
2023-03-23 10:22:37 +01:00
int jst_to_line = visible_lines ;
if ( lines_rid . size ( ) = = 1 & & jst_flags . has_flag ( TextServer : : JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE ) ) {
jst_to_line = lines_rid . size ( ) ;
} else {
if ( jst_flags . has_flag ( TextServer : : JUSTIFICATION_SKIP_LAST_LINE ) ) {
jst_to_line = visible_lines - 1 ;
}
if ( jst_flags . has_flag ( TextServer : : JUSTIFICATION_SKIP_LAST_LINE_WITH_VISIBLE_CHARS ) ) {
for ( int i = visible_lines - 1 ; i > = 0 ; i - - ) {
if ( TS - > shaped_text_has_visible_chars ( lines_rid [ i ] ) ) {
jst_to_line = i ;
break ;
}
}
}
}
2022-05-18 09:17:55 +02:00
for ( int i = 0 ; i < ( int ) lines_rid . size ( ) ; i + + ) {
2023-03-30 21:23:39 +02:00
float line_w = ( i < = dropcap_lines ) ? ( width - h_offset ) : width ;
2023-03-23 10:22:37 +01:00
if ( i < jst_to_line ) {
2023-03-30 21:23:39 +02:00
TS - > shaped_text_fit_to_width ( lines_rid [ i ] , line_w , jst_flags ) ;
2021-08-11 00:09:48 +02:00
} else if ( i = = ( visible_lines - 1 ) ) {
2023-10-01 12:39:13 +02:00
TS - > shaped_text_set_custom_ellipsis ( lines_rid [ visible_lines - 1 ] , ( el_char . length ( ) > 0 ) ? el_char [ 0 ] : 0x2026 ) ;
2023-03-30 21:23:39 +02:00
TS - > shaped_text_overrun_trim_to_width ( lines_rid [ visible_lines - 1 ] , line_w , overrun_flags ) ;
2021-08-11 00:09:48 +02:00
}
}
} else if ( lines_hidden ) {
2023-10-01 12:39:13 +02:00
TS - > shaped_text_set_custom_ellipsis ( lines_rid [ visible_lines - 1 ] , ( el_char . length ( ) > 0 ) ? el_char [ 0 ] : 0x2026 ) ;
2023-03-30 21:23:39 +02:00
TS - > shaped_text_overrun_trim_to_width ( lines_rid [ visible_lines - 1 ] , ( visible_lines - 1 < = dropcap_lines ) ? ( width - h_offset ) : width , overrun_flags ) ;
2021-08-11 00:09:48 +02:00
}
} else {
// Autowrap disabled.
2023-03-23 10:22:37 +01:00
int jst_to_line = lines_rid . size ( ) ;
if ( lines_rid . size ( ) = = 1 & & jst_flags . has_flag ( TextServer : : JUSTIFICATION_DO_NOT_SKIP_SINGLE_LINE ) ) {
jst_to_line = lines_rid . size ( ) ;
} else {
if ( jst_flags . has_flag ( TextServer : : JUSTIFICATION_SKIP_LAST_LINE ) ) {
jst_to_line = lines_rid . size ( ) - 1 ;
}
if ( jst_flags . has_flag ( TextServer : : JUSTIFICATION_SKIP_LAST_LINE_WITH_VISIBLE_CHARS ) ) {
for ( int i = lines_rid . size ( ) - 1 ; i > = 0 ; i - - ) {
if ( TS - > shaped_text_has_visible_chars ( lines_rid [ i ] ) ) {
jst_to_line = i ;
break ;
}
}
}
}
2023-03-30 21:23:39 +02:00
for ( int i = 0 ; i < ( int ) lines_rid . size ( ) ; i + + ) {
float line_w = ( i < = dropcap_lines ) ? ( width - h_offset ) : width ;
2023-03-23 10:22:37 +01:00
if ( i < jst_to_line & & alignment = = HORIZONTAL_ALIGNMENT_FILL ) {
2023-03-30 21:23:39 +02:00
TS - > shaped_text_fit_to_width ( lines_rid [ i ] , line_w , jst_flags ) ;
2022-07-11 11:40:31 +02:00
overrun_flags . set_flag ( TextServer : : OVERRUN_JUSTIFICATION_AWARE ) ;
2023-10-01 12:39:13 +02:00
TS - > shaped_text_set_custom_ellipsis ( lines_rid [ i ] , ( el_char . length ( ) > 0 ) ? el_char [ 0 ] : 0x2026 ) ;
2023-03-30 21:23:39 +02:00
TS - > shaped_text_overrun_trim_to_width ( lines_rid [ i ] , line_w , overrun_flags ) ;
TS - > shaped_text_fit_to_width ( lines_rid [ i ] , line_w , jst_flags | TextServer : : JUSTIFICATION_CONSTRAIN_ELLIPSIS ) ;
2021-08-11 00:09:48 +02:00
} else {
2023-10-01 12:39:13 +02:00
TS - > shaped_text_set_custom_ellipsis ( lines_rid [ i ] , ( el_char . length ( ) > 0 ) ? el_char [ 0 ] : 0x2026 ) ;
2023-03-30 21:23:39 +02:00
TS - > shaped_text_overrun_trim_to_width ( lines_rid [ i ] , line_w , overrun_flags ) ;
2021-08-11 00:09:48 +02:00
}
2020-09-03 13:22:16 +02:00
}
}
2021-08-11 00:09:48 +02:00
lines_dirty = false ;
2020-09-03 13:22:16 +02:00
}
}
RID TextParagraph : : get_rid ( ) const {
return rid ;
}
RID TextParagraph : : get_line_rid ( int p_line ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND_V ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) , RID ( ) ) ;
2021-08-11 00:09:48 +02:00
return lines_rid [ p_line ] ;
2020-09-03 13:22:16 +02:00
}
2020-11-19 15:45:23 +01:00
RID TextParagraph : : get_dropcap_rid ( ) const {
return dropcap_rid ;
}
2020-09-03 13:22:16 +02:00
void TextParagraph : : clear ( ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2022-12-29 01:24:45 +01:00
for ( const RID & line_rid : lines_rid ) {
TS - > free_rid ( line_rid ) ;
2020-09-03 13:22:16 +02:00
}
2021-08-11 00:09:48 +02:00
lines_rid . clear ( ) ;
2020-09-03 13:22:16 +02:00
TS - > shaped_text_clear ( rid ) ;
2020-11-19 15:45:23 +01:00
TS - > shaped_text_clear ( dropcap_rid ) ;
2020-09-03 13:22:16 +02:00
}
void TextParagraph : : set_preserve_invalid ( bool p_enabled ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
TS - > shaped_text_set_preserve_invalid ( rid , p_enabled ) ;
2020-11-19 15:45:23 +01:00
TS - > shaped_text_set_preserve_invalid ( dropcap_rid , p_enabled ) ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
}
bool TextParagraph : : get_preserve_invalid ( ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
return TS - > shaped_text_get_preserve_invalid ( rid ) ;
}
void TextParagraph : : set_preserve_control ( bool p_enabled ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
TS - > shaped_text_set_preserve_control ( rid , p_enabled ) ;
2020-11-19 15:45:23 +01:00
TS - > shaped_text_set_preserve_control ( dropcap_rid , p_enabled ) ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
}
bool TextParagraph : : get_preserve_control ( ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
return TS - > shaped_text_get_preserve_control ( rid ) ;
}
void TextParagraph : : set_direction ( TextServer : : Direction p_direction ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
TS - > shaped_text_set_direction ( rid , p_direction ) ;
2020-11-19 15:45:23 +01:00
TS - > shaped_text_set_direction ( dropcap_rid , p_direction ) ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
}
TextServer : : Direction TextParagraph : : get_direction ( ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
return TS - > shaped_text_get_direction ( rid ) ;
}
2021-03-06 10:52:16 +01:00
void TextParagraph : : set_custom_punctuation ( const String & p_punct ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2021-03-06 10:52:16 +01:00
TS - > shaped_text_set_custom_punctuation ( rid , p_punct ) ;
lines_dirty = true ;
}
String TextParagraph : : get_custom_punctuation ( ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2021-03-06 10:52:16 +01:00
return TS - > shaped_text_get_custom_punctuation ( rid ) ;
}
2020-09-03 13:22:16 +02:00
void TextParagraph : : set_orientation ( TextServer : : Orientation p_orientation ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
TS - > shaped_text_set_orientation ( rid , p_orientation ) ;
2020-11-19 15:45:23 +01:00
TS - > shaped_text_set_orientation ( dropcap_rid , p_orientation ) ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
}
TextServer : : Orientation TextParagraph : : get_orientation ( ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
return TS - > shaped_text_get_orientation ( rid ) ;
}
2022-05-09 11:47:10 +02:00
bool TextParagraph : : set_dropcap ( const String & p_text , const Ref < Font > & p_font , int p_font_size , const Rect2 & p_dropcap_margins , const String & p_language ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2022-05-09 11:47:10 +02:00
ERR_FAIL_COND_V ( p_font . is_null ( ) , false ) ;
2020-11-19 15:45:23 +01:00
TS - > shaped_text_clear ( dropcap_rid ) ;
dropcap_margins = p_dropcap_margins ;
2022-05-09 11:47:10 +02:00
bool res = TS - > shaped_text_add_string ( dropcap_rid , p_text , p_font - > get_rids ( ) , p_font_size , p_font - > get_opentype_features ( ) , p_language ) ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-11-19 15:45:23 +01:00
return res ;
}
void TextParagraph : : clear_dropcap ( ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-11-19 15:45:23 +01:00
dropcap_margins = Rect2 ( ) ;
TS - > shaped_text_clear ( dropcap_rid ) ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-11-19 15:45:23 +01:00
}
2022-05-09 11:47:10 +02:00
bool TextParagraph : : add_string ( const String & p_text , const Ref < Font > & p_font , int p_font_size , const String & p_language , const Variant & p_meta ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2022-05-09 11:47:10 +02:00
ERR_FAIL_COND_V ( p_font . is_null ( ) , false ) ;
bool res = TS - > shaped_text_add_string ( rid , p_text , p_font - > get_rids ( ) , p_font_size , p_font - > get_opentype_features ( ) , p_language , p_meta ) ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
return res ;
}
2021-08-27 23:19:51 +02:00
void TextParagraph : : set_bidi_override ( const Array & p_override ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
TS - > shaped_text_set_bidi_override ( rid , p_override ) ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
}
2022-12-08 21:01:07 +01:00
bool TextParagraph : : add_object ( Variant p_key , const Size2 & p_size , InlineAlignment p_inline_align , int p_length , float p_baseline ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2022-12-08 21:01:07 +01:00
bool res = TS - > shaped_text_add_object ( rid , p_key , p_size , p_inline_align , p_length , p_baseline ) ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
return res ;
}
2022-12-08 21:01:07 +01:00
bool TextParagraph : : resize_object ( Variant p_key , const Size2 & p_size , InlineAlignment p_inline_align , float p_baseline ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2022-12-08 21:01:07 +01:00
bool res = TS - > shaped_text_resize_object ( rid , p_key , p_size , p_inline_align , p_baseline ) ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
return res ;
}
2021-11-25 03:58:47 +01:00
void TextParagraph : : set_alignment ( HorizontalAlignment p_alignment ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2021-11-25 03:58:47 +01:00
if ( alignment ! = p_alignment ) {
if ( alignment = = HORIZONTAL_ALIGNMENT_FILL | | p_alignment = = HORIZONTAL_ALIGNMENT_FILL ) {
alignment = p_alignment ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
} else {
2021-11-25 03:58:47 +01:00
alignment = p_alignment ;
2020-09-03 13:22:16 +02:00
}
}
}
2021-11-25 03:58:47 +01:00
HorizontalAlignment TextParagraph : : get_alignment ( ) const {
return alignment ;
2020-09-03 13:22:16 +02:00
}
void TextParagraph : : tab_align ( const Vector < float > & p_tab_stops ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
tab_stops = p_tab_stops ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
}
2022-07-11 11:40:31 +02:00
void TextParagraph : : set_justification_flags ( BitField < TextServer : : JustificationFlag > p_flags ) {
_THREAD_SAFE_METHOD_
if ( jst_flags ! = p_flags ) {
jst_flags = p_flags ;
lines_dirty = true ;
}
}
BitField < TextServer : : JustificationFlag > TextParagraph : : get_justification_flags ( ) const {
return jst_flags ;
}
void TextParagraph : : set_break_flags ( BitField < TextServer : : LineBreakFlag > p_flags ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2022-07-11 11:40:31 +02:00
if ( brk_flags ! = p_flags ) {
brk_flags = p_flags ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
}
}
2022-07-11 11:40:31 +02:00
BitField < TextServer : : LineBreakFlag > TextParagraph : : get_break_flags ( ) const {
return brk_flags ;
2020-09-03 13:22:16 +02:00
}
2022-06-15 10:01:45 +02:00
void TextParagraph : : set_text_overrun_behavior ( TextServer : : OverrunBehavior p_behavior ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2021-08-11 00:09:48 +02:00
if ( overrun_behavior ! = p_behavior ) {
overrun_behavior = p_behavior ;
lines_dirty = true ;
}
}
2022-06-15 10:01:45 +02:00
TextServer : : OverrunBehavior TextParagraph : : get_text_overrun_behavior ( ) const {
2021-08-11 00:09:48 +02:00
return overrun_behavior ;
}
2023-10-01 12:39:13 +02:00
void TextParagraph : : set_ellipsis_char ( const String & p_char ) {
String c = p_char ;
if ( c . length ( ) > 1 ) {
WARN_PRINT ( " Ellipsis must be exactly one character long ( " + itos ( c . length ( ) ) + " characters given). " ) ;
c = c . left ( 1 ) ;
}
if ( el_char = = c ) {
return ;
}
el_char = c ;
lines_dirty = true ;
}
String TextParagraph : : get_ellipsis_char ( ) const {
return el_char ;
}
2020-09-03 13:22:16 +02:00
void TextParagraph : : set_width ( float p_width ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
if ( width ! = p_width ) {
width = p_width ;
2021-08-11 00:09:48 +02:00
lines_dirty = true ;
2020-09-03 13:22:16 +02:00
}
}
float TextParagraph : : get_width ( ) const {
return width ;
}
2021-10-19 21:38:58 +02:00
Size2 TextParagraph : : get_non_wrapped_size ( ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2023-05-30 11:47:50 +02:00
return TS - > shaped_text_get_size ( rid ) ;
2020-09-03 13:22:16 +02:00
}
Size2 TextParagraph : : get_size ( ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2024-08-29 08:37:23 +02:00
float h_offset = 0.f ;
float v_offset = 0.f ;
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . x + dropcap_margins . size . x + dropcap_margins . position . x ;
v_offset = TS - > shaped_text_get_size ( dropcap_rid ) . y + dropcap_margins . size . y + dropcap_margins . position . y ;
} else {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . y + dropcap_margins . size . y + dropcap_margins . position . y ;
v_offset = TS - > shaped_text_get_size ( dropcap_rid ) . x + dropcap_margins . size . x + dropcap_margins . position . x ;
}
2020-09-03 13:22:16 +02:00
Size2 size ;
2022-05-18 09:17:55 +02:00
int visible_lines = ( max_lines_visible > = 0 ) ? MIN ( max_lines_visible , ( int ) lines_rid . size ( ) ) : ( int ) lines_rid . size ( ) ;
2021-08-21 00:22:09 +02:00
for ( int i = 0 ; i < visible_lines ; i + + ) {
2021-08-11 00:09:48 +02:00
Size2 lsize = TS - > shaped_text_get_size ( lines_rid [ i ] ) ;
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2024-08-29 08:37:23 +02:00
if ( h_offset > 0 & & i < = dropcap_lines ) {
lsize . x + = h_offset ;
}
2020-09-03 13:22:16 +02:00
size . x = MAX ( size . x , lsize . x ) ;
2022-05-09 11:47:10 +02:00
size . y + = lsize . y ;
2020-09-03 13:22:16 +02:00
} else {
2024-08-29 08:37:23 +02:00
if ( h_offset > 0 & & i < = dropcap_lines ) {
lsize . y + = h_offset ;
}
2022-05-09 11:47:10 +02:00
size . x + = lsize . x ;
2020-09-03 13:22:16 +02:00
size . y = MAX ( size . y , lsize . y ) ;
}
}
2024-08-29 08:37:23 +02:00
if ( h_offset > 0 ) {
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
size . y = MAX ( size . y , v_offset ) ;
} else {
size . x = MAX ( size . x , v_offset ) ;
}
}
2020-09-03 13:22:16 +02:00
return size ;
}
int TextParagraph : : get_line_count ( ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
return ( int ) lines_rid . size ( ) ;
2021-08-11 00:09:48 +02:00
}
void TextParagraph : : set_max_lines_visible ( int p_lines ) {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2021-08-11 00:09:48 +02:00
if ( p_lines ! = max_lines_visible ) {
max_lines_visible = p_lines ;
lines_dirty = true ;
}
}
int TextParagraph : : get_max_lines_visible ( ) const {
return max_lines_visible ;
2020-09-03 13:22:16 +02:00
}
Array TextParagraph : : get_line_objects ( int p_line ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND_V ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) , Array ( ) ) ;
2021-08-11 00:09:48 +02:00
return TS - > shaped_text_get_objects ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
}
Rect2 TextParagraph : : get_line_object_rect ( int p_line , Variant p_key ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND_V ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) , Rect2 ( ) ) ;
2022-10-26 09:46:08 +02:00
Vector2 ofs ;
float h_offset = 0.f ;
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . x + dropcap_margins . size . x + dropcap_margins . position . x ;
} else {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . y + dropcap_margins . size . y + dropcap_margins . position . y ;
}
for ( int i = 0 ; i < = p_line ; i + + ) {
float l_width = width ;
2021-08-11 00:09:48 +02:00
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2022-10-26 09:46:08 +02:00
ofs . x = 0.f ;
ofs . y + = TS - > shaped_text_get_ascent ( lines_rid [ i ] ) ;
if ( i < = dropcap_lines ) {
if ( TS - > shaped_text_get_inferred_direction ( dropcap_rid ) = = TextServer : : DIRECTION_LTR ) {
ofs . x - = h_offset ;
}
l_width - = h_offset ;
}
2020-09-03 13:22:16 +02:00
} else {
2022-10-26 09:46:08 +02:00
ofs . y = 0.f ;
ofs . x + = TS - > shaped_text_get_ascent ( lines_rid [ i ] ) ;
if ( i < = dropcap_lines ) {
if ( TS - > shaped_text_get_inferred_direction ( dropcap_rid ) = = TextServer : : DIRECTION_LTR ) {
2024-08-29 08:37:23 +02:00
ofs . y - = h_offset ;
2022-10-26 09:46:08 +02:00
}
l_width - = h_offset ;
}
}
float length = TS - > shaped_text_get_width ( lines_rid [ i ] ) ;
if ( width > 0 ) {
switch ( alignment ) {
case HORIZONTAL_ALIGNMENT_FILL :
if ( TS - > shaped_text_get_inferred_direction ( lines_rid [ i ] ) = = TextServer : : DIRECTION_RTL ) {
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x + = l_width - length ;
} else {
ofs . y + = l_width - length ;
}
}
break ;
case HORIZONTAL_ALIGNMENT_LEFT :
break ;
case HORIZONTAL_ALIGNMENT_CENTER : {
if ( length < = l_width ) {
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x + = Math : : floor ( ( l_width - length ) / 2.0 ) ;
} else {
ofs . y + = Math : : floor ( ( l_width - length ) / 2.0 ) ;
}
} else if ( TS - > shaped_text_get_inferred_direction ( lines_rid [ i ] ) = = TextServer : : DIRECTION_RTL ) {
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x + = l_width - length ;
} else {
ofs . y + = l_width - length ;
}
}
} break ;
case HORIZONTAL_ALIGNMENT_RIGHT : {
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x + = l_width - length ;
} else {
ofs . y + = l_width - length ;
}
} break ;
}
}
if ( i ! = p_line ) {
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x = 0.f ;
ofs . y + = TS - > shaped_text_get_descent ( lines_rid [ i ] ) ;
} else {
ofs . y = 0.f ;
ofs . x + = TS - > shaped_text_get_descent ( lines_rid [ i ] ) ;
}
2020-09-03 13:22:16 +02:00
}
}
2022-10-26 09:46:08 +02:00
Rect2 rect = TS - > shaped_text_get_object_rect ( lines_rid [ p_line ] , p_key ) ;
rect . position + = ofs ;
return rect ;
2020-09-03 13:22:16 +02:00
}
Size2 TextParagraph : : get_line_size ( int p_line ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND_V ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) , Size2 ( ) ) ;
2023-05-30 11:47:50 +02:00
return TS - > shaped_text_get_size ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
}
Vector2i TextParagraph : : get_line_range ( int p_line ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND_V ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) , Vector2i ( ) ) ;
2021-08-11 00:09:48 +02:00
return TS - > shaped_text_get_range ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
}
float TextParagraph : : get_line_ascent ( int p_line ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND_V ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) , 0.f ) ;
2022-05-09 11:47:10 +02:00
return TS - > shaped_text_get_ascent ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
}
float TextParagraph : : get_line_descent ( int p_line ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND_V ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) , 0.f ) ;
2022-05-09 11:47:10 +02:00
return TS - > shaped_text_get_descent ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
}
float TextParagraph : : get_line_width ( int p_line ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND_V ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) , 0.f ) ;
2021-08-11 00:09:48 +02:00
return TS - > shaped_text_get_width ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
}
float TextParagraph : : get_line_underline_position ( int p_line ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND_V ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) , 0.f ) ;
2021-08-11 00:09:48 +02:00
return TS - > shaped_text_get_underline_position ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
}
float TextParagraph : : get_line_underline_thickness ( int p_line ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND_V ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) , 0.f ) ;
2021-08-11 00:09:48 +02:00
return TS - > shaped_text_get_underline_thickness ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
}
2020-11-19 15:45:23 +01:00
Size2 TextParagraph : : get_dropcap_size ( ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-11-19 15:45:23 +01:00
return TS - > shaped_text_get_size ( dropcap_rid ) + dropcap_margins . size + dropcap_margins . position ;
}
int TextParagraph : : get_dropcap_lines ( ) const {
return dropcap_lines ;
}
void TextParagraph : : draw ( RID p_canvas , const Vector2 & p_pos , const Color & p_color , const Color & p_dc_color ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
Vector2 ofs = p_pos ;
2020-11-19 15:45:23 +01:00
float h_offset = 0.f ;
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . x + dropcap_margins . size . x + dropcap_margins . position . x ;
} else {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . y + dropcap_margins . size . y + dropcap_margins . position . y ;
}
if ( h_offset > 0 ) {
// Draw dropcap.
Vector2 dc_off = ofs ;
2022-01-10 16:24:03 +01:00
if ( TS - > shaped_text_get_inferred_direction ( dropcap_rid ) = = TextServer : : DIRECTION_RTL ) {
2020-11-19 15:45:23 +01:00
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
dc_off . x + = width - h_offset ;
} else {
dc_off . y + = width - h_offset ;
}
}
TS - > shaped_text_draw ( dropcap_rid , p_canvas , dc_off + Vector2 ( 0 , TS - > shaped_text_get_ascent ( dropcap_rid ) + dropcap_margins . size . y + dropcap_margins . position . y / 2 ) , - 1 , - 1 , p_dc_color ) ;
}
2022-05-18 09:17:55 +02:00
int lines_visible = ( max_lines_visible > = 0 ) ? MIN ( max_lines_visible , ( int ) lines_rid . size ( ) ) : ( int ) lines_rid . size ( ) ;
2021-08-11 00:09:48 +02:00
for ( int i = 0 ; i < lines_visible ; i + + ) {
2020-11-19 15:45:23 +01:00
float l_width = width ;
2021-08-11 00:09:48 +02:00
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2020-09-03 13:22:16 +02:00
ofs . x = p_pos . x ;
2022-05-09 11:47:10 +02:00
ofs . y + = TS - > shaped_text_get_ascent ( lines_rid [ i ] ) ;
2020-11-19 15:45:23 +01:00
if ( i < = dropcap_lines ) {
2022-01-10 16:24:03 +01:00
if ( TS - > shaped_text_get_inferred_direction ( dropcap_rid ) = = TextServer : : DIRECTION_LTR ) {
2020-11-19 15:45:23 +01:00
ofs . x - = h_offset ;
}
l_width - = h_offset ;
}
2020-09-03 13:22:16 +02:00
} else {
ofs . y = p_pos . y ;
2022-05-09 11:47:10 +02:00
ofs . x + = TS - > shaped_text_get_ascent ( lines_rid [ i ] ) ;
2020-11-19 15:45:23 +01:00
if ( i < = dropcap_lines ) {
2022-01-10 16:24:03 +01:00
if ( TS - > shaped_text_get_inferred_direction ( dropcap_rid ) = = TextServer : : DIRECTION_LTR ) {
2024-08-29 08:37:23 +02:00
ofs . y - = h_offset ;
2020-11-19 15:45:23 +01:00
}
l_width - = h_offset ;
}
2020-09-03 13:22:16 +02:00
}
2021-08-21 00:22:09 +02:00
float line_width = TS - > shaped_text_get_width ( lines_rid [ i ] ) ;
2020-09-03 13:22:16 +02:00
if ( width > 0 ) {
2021-11-25 03:58:47 +01:00
switch ( alignment ) {
case HORIZONTAL_ALIGNMENT_FILL :
2022-01-10 16:24:03 +01:00
if ( TS - > shaped_text_get_inferred_direction ( lines_rid [ i ] ) = = TextServer : : DIRECTION_RTL ) {
2021-08-11 00:09:48 +02:00
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2021-08-21 00:22:09 +02:00
ofs . x + = l_width - line_width ;
2021-08-11 00:09:48 +02:00
} else {
2021-08-21 00:22:09 +02:00
ofs . y + = l_width - line_width ;
2021-08-11 00:09:48 +02:00
}
}
break ;
2021-11-25 03:58:47 +01:00
case HORIZONTAL_ALIGNMENT_LEFT :
2020-09-03 13:22:16 +02:00
break ;
2021-11-25 03:58:47 +01:00
case HORIZONTAL_ALIGNMENT_CENTER : {
2022-04-04 08:04:05 +02:00
if ( line_width < = l_width ) {
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x + = Math : : floor ( ( l_width - line_width ) / 2.0 ) ;
} else {
ofs . y + = Math : : floor ( ( l_width - line_width ) / 2.0 ) ;
}
} else if ( TS - > shaped_text_get_inferred_direction ( lines_rid [ i ] ) = = TextServer : : DIRECTION_RTL ) {
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x + = l_width - line_width ;
} else {
ofs . y + = l_width - line_width ;
}
2020-09-03 13:22:16 +02:00
}
} break ;
2021-11-25 03:58:47 +01:00
case HORIZONTAL_ALIGNMENT_RIGHT : {
2021-08-11 00:09:48 +02:00
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2021-08-21 00:22:09 +02:00
ofs . x + = l_width - line_width ;
2020-09-03 13:22:16 +02:00
} else {
2021-08-21 00:22:09 +02:00
ofs . y + = l_width - line_width ;
2020-09-03 13:22:16 +02:00
}
} break ;
}
}
float clip_l ;
2021-08-11 00:09:48 +02:00
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2020-09-03 13:22:16 +02:00
clip_l = MAX ( 0 , p_pos . x - ofs . x ) ;
} else {
clip_l = MAX ( 0 , p_pos . y - ofs . y ) ;
}
2021-08-11 00:09:48 +02:00
TS - > shaped_text_draw ( lines_rid [ i ] , p_canvas , ofs , clip_l , clip_l + l_width , p_color ) ;
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2020-09-03 13:22:16 +02:00
ofs . x = p_pos . x ;
2022-05-09 11:47:10 +02:00
ofs . y + = TS - > shaped_text_get_descent ( lines_rid [ i ] ) ;
2020-09-03 13:22:16 +02:00
} else {
ofs . y = p_pos . y ;
2022-05-09 11:47:10 +02:00
ofs . x + = TS - > shaped_text_get_descent ( lines_rid [ i ] ) ;
2020-09-03 13:22:16 +02:00
}
}
}
2020-11-19 15:45:23 +01:00
void TextParagraph : : draw_outline ( RID p_canvas , const Vector2 & p_pos , int p_outline_size , const Color & p_color , const Color & p_dc_color ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
Vector2 ofs = p_pos ;
2020-11-19 15:45:23 +01:00
float h_offset = 0.f ;
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . x + dropcap_margins . size . x + dropcap_margins . position . x ;
} else {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . y + dropcap_margins . size . y + dropcap_margins . position . y ;
}
if ( h_offset > 0 ) {
// Draw dropcap.
Vector2 dc_off = ofs ;
2022-01-10 16:24:03 +01:00
if ( TS - > shaped_text_get_inferred_direction ( dropcap_rid ) = = TextServer : : DIRECTION_RTL ) {
2020-11-19 15:45:23 +01:00
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
dc_off . x + = width - h_offset ;
} else {
dc_off . y + = width - h_offset ;
}
}
TS - > shaped_text_draw_outline ( dropcap_rid , p_canvas , dc_off + Vector2 ( dropcap_margins . position . x , TS - > shaped_text_get_ascent ( dropcap_rid ) + dropcap_margins . position . y ) , - 1 , - 1 , p_outline_size , p_dc_color ) ;
}
2022-05-18 09:17:55 +02:00
for ( int i = 0 ; i < ( int ) lines_rid . size ( ) ; i + + ) {
2020-11-19 15:45:23 +01:00
float l_width = width ;
2021-08-11 00:09:48 +02:00
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2020-09-03 13:22:16 +02:00
ofs . x = p_pos . x ;
2022-05-09 11:47:10 +02:00
ofs . y + = TS - > shaped_text_get_ascent ( lines_rid [ i ] ) ;
2020-11-19 15:45:23 +01:00
if ( i < = dropcap_lines ) {
2022-01-10 16:24:03 +01:00
if ( TS - > shaped_text_get_inferred_direction ( dropcap_rid ) = = TextServer : : DIRECTION_LTR ) {
2020-11-19 15:45:23 +01:00
ofs . x - = h_offset ;
}
l_width - = h_offset ;
}
2020-09-03 13:22:16 +02:00
} else {
ofs . y = p_pos . y ;
2022-05-09 11:47:10 +02:00
ofs . x + = TS - > shaped_text_get_ascent ( lines_rid [ i ] ) ;
2020-11-19 15:45:23 +01:00
if ( i < = dropcap_lines ) {
2022-01-10 16:24:03 +01:00
if ( TS - > shaped_text_get_inferred_direction ( dropcap_rid ) = = TextServer : : DIRECTION_LTR ) {
2024-08-29 08:37:23 +02:00
ofs . y - = h_offset ;
2020-11-19 15:45:23 +01:00
}
l_width - = h_offset ;
}
2020-09-03 13:22:16 +02:00
}
2021-08-11 00:09:48 +02:00
float length = TS - > shaped_text_get_width ( lines_rid [ i ] ) ;
2020-09-03 13:22:16 +02:00
if ( width > 0 ) {
2021-11-25 03:58:47 +01:00
switch ( alignment ) {
case HORIZONTAL_ALIGNMENT_FILL :
2022-01-10 16:24:03 +01:00
if ( TS - > shaped_text_get_inferred_direction ( lines_rid [ i ] ) = = TextServer : : DIRECTION_RTL ) {
2021-08-11 00:09:48 +02:00
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x + = l_width - length ;
} else {
ofs . y + = l_width - length ;
}
}
break ;
2021-11-25 03:58:47 +01:00
case HORIZONTAL_ALIGNMENT_LEFT :
2020-09-03 13:22:16 +02:00
break ;
2021-11-25 03:58:47 +01:00
case HORIZONTAL_ALIGNMENT_CENTER : {
2022-04-04 08:04:05 +02:00
if ( length < = l_width ) {
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x + = Math : : floor ( ( l_width - length ) / 2.0 ) ;
} else {
ofs . y + = Math : : floor ( ( l_width - length ) / 2.0 ) ;
}
} else if ( TS - > shaped_text_get_inferred_direction ( lines_rid [ i ] ) = = TextServer : : DIRECTION_RTL ) {
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x + = l_width - length ;
} else {
ofs . y + = l_width - length ;
}
2020-09-03 13:22:16 +02:00
}
} break ;
2021-11-25 03:58:47 +01:00
case HORIZONTAL_ALIGNMENT_RIGHT : {
2021-08-11 00:09:48 +02:00
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2020-11-19 15:45:23 +01:00
ofs . x + = l_width - length ;
2020-09-03 13:22:16 +02:00
} else {
2020-11-19 15:45:23 +01:00
ofs . y + = l_width - length ;
2020-09-03 13:22:16 +02:00
}
} break ;
}
}
float clip_l ;
2021-08-11 00:09:48 +02:00
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2020-09-03 13:22:16 +02:00
clip_l = MAX ( 0 , p_pos . x - ofs . x ) ;
} else {
clip_l = MAX ( 0 , p_pos . y - ofs . y ) ;
}
2021-08-11 00:09:48 +02:00
TS - > shaped_text_draw_outline ( lines_rid [ i ] , p_canvas , ofs , clip_l , clip_l + l_width , p_outline_size , p_color ) ;
if ( TS - > shaped_text_get_orientation ( lines_rid [ i ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2020-09-03 13:22:16 +02:00
ofs . x = p_pos . x ;
2022-05-09 11:47:10 +02:00
ofs . y + = TS - > shaped_text_get_descent ( lines_rid [ i ] ) ;
2020-09-03 13:22:16 +02:00
} else {
ofs . y = p_pos . y ;
2022-05-09 11:47:10 +02:00
ofs . x + = TS - > shaped_text_get_descent ( lines_rid [ i ] ) ;
2020-09-03 13:22:16 +02:00
}
}
}
int TextParagraph : : hit_test ( const Point2 & p_coords ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
Vector2 ofs ;
if ( TS - > shaped_text_get_orientation ( rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2021-04-05 14:09:59 +02:00
if ( ofs . y < 0 ) {
2020-09-03 13:22:16 +02:00
return 0 ;
2021-04-05 14:09:59 +02:00
}
2020-09-03 13:22:16 +02:00
} else {
2021-04-05 14:09:59 +02:00
if ( ofs . x < 0 ) {
2020-09-03 13:22:16 +02:00
return 0 ;
2021-04-05 14:09:59 +02:00
}
2020-09-03 13:22:16 +02:00
}
2022-12-29 01:24:45 +01:00
for ( const RID & line_rid : lines_rid ) {
if ( TS - > shaped_text_get_orientation ( line_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
if ( ( p_coords . y > = ofs . y ) & & ( p_coords . y < = ofs . y + TS - > shaped_text_get_size ( line_rid ) . y ) ) {
return TS - > shaped_text_hit_test_position ( line_rid , p_coords . x ) ;
2020-09-03 13:22:16 +02:00
}
2022-12-29 01:24:45 +01:00
ofs . y + = TS - > shaped_text_get_size ( line_rid ) . y ;
2020-09-03 13:22:16 +02:00
} else {
2022-12-29 01:24:45 +01:00
if ( ( p_coords . x > = ofs . x ) & & ( p_coords . x < = ofs . x + TS - > shaped_text_get_size ( line_rid ) . x ) ) {
return TS - > shaped_text_hit_test_position ( line_rid , p_coords . y ) ;
2020-09-03 13:22:16 +02:00
}
2022-12-29 01:24:45 +01:00
ofs . y + = TS - > shaped_text_get_size ( line_rid ) . x ;
2020-09-03 13:22:16 +02:00
}
}
return TS - > shaped_text_get_range ( rid ) . y ;
}
2020-11-19 15:45:23 +01:00
void TextParagraph : : draw_dropcap ( RID p_canvas , const Vector2 & p_pos , const Color & p_color ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-11-19 15:45:23 +01:00
Vector2 ofs = p_pos ;
float h_offset = 0.f ;
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . x + dropcap_margins . size . x + dropcap_margins . position . x ;
} else {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . y + dropcap_margins . size . y + dropcap_margins . position . y ;
}
if ( h_offset > 0 ) {
// Draw dropcap.
2022-01-10 16:24:03 +01:00
if ( TS - > shaped_text_get_inferred_direction ( dropcap_rid ) = = TextServer : : DIRECTION_RTL ) {
2020-11-19 15:45:23 +01:00
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x + = width - h_offset ;
} else {
ofs . y + = width - h_offset ;
}
}
TS - > shaped_text_draw ( dropcap_rid , p_canvas , ofs + Vector2 ( dropcap_margins . position . x , TS - > shaped_text_get_ascent ( dropcap_rid ) + dropcap_margins . position . y ) , - 1 , - 1 , p_color ) ;
}
}
void TextParagraph : : draw_dropcap_outline ( RID p_canvas , const Vector2 & p_pos , int p_outline_size , const Color & p_color ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-11-19 15:45:23 +01:00
Vector2 ofs = p_pos ;
float h_offset = 0.f ;
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . x + dropcap_margins . size . x + dropcap_margins . position . x ;
} else {
h_offset = TS - > shaped_text_get_size ( dropcap_rid ) . y + dropcap_margins . size . y + dropcap_margins . position . y ;
}
if ( h_offset > 0 ) {
// Draw dropcap.
2022-01-10 16:24:03 +01:00
if ( TS - > shaped_text_get_inferred_direction ( dropcap_rid ) = = TextServer : : DIRECTION_RTL ) {
2020-11-19 15:45:23 +01:00
if ( TS - > shaped_text_get_orientation ( dropcap_rid ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
ofs . x + = width - h_offset ;
} else {
ofs . y + = width - h_offset ;
}
}
TS - > shaped_text_draw_outline ( dropcap_rid , p_canvas , ofs + Vector2 ( dropcap_margins . position . x , TS - > shaped_text_get_ascent ( dropcap_rid ) + dropcap_margins . position . y ) , - 1 , - 1 , p_outline_size , p_color ) ;
}
}
2020-09-03 13:22:16 +02:00
void TextParagraph : : draw_line ( RID p_canvas , const Vector2 & p_pos , int p_line , const Color & p_color ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) ) ;
2020-09-03 13:22:16 +02:00
Vector2 ofs = p_pos ;
2020-11-19 15:45:23 +01:00
2021-08-11 00:09:48 +02:00
if ( TS - > shaped_text_get_orientation ( lines_rid [ p_line ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2022-05-09 11:47:10 +02:00
ofs . y + = TS - > shaped_text_get_ascent ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
} else {
2022-05-09 11:47:10 +02:00
ofs . x + = TS - > shaped_text_get_ascent ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
}
2021-08-11 00:09:48 +02:00
return TS - > shaped_text_draw ( lines_rid [ p_line ] , p_canvas , ofs , - 1 , - 1 , p_color ) ;
2020-09-03 13:22:16 +02:00
}
void TextParagraph : : draw_line_outline ( RID p_canvas , const Vector2 & p_pos , int p_line , int p_outline_size , const Color & p_color ) const {
2022-05-18 09:17:55 +02:00
_THREAD_SAFE_METHOD_
2020-09-03 13:22:16 +02:00
const_cast < TextParagraph * > ( this ) - > _shape_lines ( ) ;
2022-05-18 09:17:55 +02:00
ERR_FAIL_COND ( p_line < 0 | | p_line > = ( int ) lines_rid . size ( ) ) ;
2020-09-03 13:22:16 +02:00
Vector2 ofs = p_pos ;
2021-08-11 00:09:48 +02:00
if ( TS - > shaped_text_get_orientation ( lines_rid [ p_line ] ) = = TextServer : : ORIENTATION_HORIZONTAL ) {
2022-05-09 11:47:10 +02:00
ofs . y + = TS - > shaped_text_get_ascent ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
} else {
2022-05-09 11:47:10 +02:00
ofs . x + = TS - > shaped_text_get_ascent ( lines_rid [ p_line ] ) ;
2020-09-03 13:22:16 +02:00
}
2021-08-11 00:09:48 +02:00
return TS - > shaped_text_draw_outline ( lines_rid [ p_line ] , p_canvas , ofs , - 1 , - 1 , p_outline_size , p_color ) ;
2020-09-03 13:22:16 +02:00
}
2022-05-09 11:47:10 +02:00
TextParagraph : : TextParagraph ( const String & p_text , const Ref < Font > & p_font , int p_font_size , const String & p_language , float p_width , TextServer : : Direction p_direction , TextServer : : Orientation p_orientation ) {
2020-09-03 13:22:16 +02:00
rid = TS - > create_shaped_text ( p_direction , p_orientation ) ;
2022-05-09 11:47:10 +02:00
if ( p_font . is_valid ( ) ) {
TS - > shaped_text_add_string ( rid , p_text , p_font - > get_rids ( ) , p_font_size , p_font - > get_opentype_features ( ) , p_language ) ;
}
2020-09-03 13:22:16 +02:00
width = p_width ;
}
TextParagraph : : TextParagraph ( ) {
rid = TS - > create_shaped_text ( ) ;
2020-11-19 15:45:23 +01:00
dropcap_rid = TS - > create_shaped_text ( ) ;
2020-09-03 13:22:16 +02:00
}
TextParagraph : : ~ TextParagraph ( ) {
2022-12-29 01:24:45 +01:00
for ( const RID & line_rid : lines_rid ) {
TS - > free_rid ( line_rid ) ;
2020-09-03 13:22:16 +02:00
}
2021-08-11 00:09:48 +02:00
lines_rid . clear ( ) ;
2022-02-13 13:41:29 +01:00
TS - > free_rid ( rid ) ;
TS - > free_rid ( dropcap_rid ) ;
2020-09-03 13:22:16 +02:00
}