@@ -40,8 +40,18 @@ void CodeEdit::_notification(int p_what) {
4040 switch (p_what) {
4141 case NOTIFICATION_THEME_CHANGED: {
4242 set_gutter_width (main_gutter, get_line_height ());
43- set_gutter_width (line_number_gutter, (line_number_digits + 1 ) * theme_cache. font -> get_char_size ( ' 0 ' , theme_cache. font_size ). width );
43+ _update_line_number_gutter_width ( );
4444 set_gutter_width (fold_gutter, get_line_height () / 1.2 );
45+ _clear_line_number_text_cache ();
46+ } break ;
47+
48+ case NOTIFICATION_TRANSLATION_CHANGED:
49+ [[fallthrough]];
50+ case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
51+ [[fallthrough]];
52+ case NOTIFICATION_VISIBILITY_CHANGED: {
53+ // Avoid having many hidden text editors with unused cache filling up memory.
54+ _clear_line_number_text_cache ();
4555 } break ;
4656
4757 case NOTIFICATION_DRAW: {
@@ -1287,9 +1297,9 @@ bool CodeEdit::is_drawing_executing_lines_gutter() const {
12871297}
12881298
12891299void CodeEdit::_main_gutter_draw_callback (int p_line, int p_gutter, const Rect2 &p_region) {
1300+ bool hovering = get_hovered_gutter () == Vector2i (main_gutter, p_line);
12901301 if (draw_breakpoints && theme_cache.breakpoint_icon .is_valid ()) {
12911302 bool breakpointed = is_line_breakpointed (p_line);
1292- bool hovering = p_region.has_point (get_local_mouse_pos ());
12931303 bool shift_pressed = Input::get_singleton ()->is_key_pressed (Key::SHIFT);
12941304
12951305 if (breakpointed || (hovering && !is_dragging_cursor () && !shift_pressed)) {
@@ -1308,7 +1318,6 @@ void CodeEdit::_main_gutter_draw_callback(int p_line, int p_gutter, const Rect2
13081318
13091319 if (draw_bookmarks && theme_cache.bookmark_icon .is_valid ()) {
13101320 bool bookmarked = is_line_bookmarked (p_line);
1311- bool hovering = p_region.has_point (get_local_mouse_pos ());
13121321 bool shift_pressed = Input::get_singleton ()->is_key_pressed (Key::SHIFT);
13131322
13141323 if (bookmarked || (hovering && !is_dragging_cursor () && shift_pressed)) {
@@ -1442,7 +1451,13 @@ bool CodeEdit::is_draw_line_numbers_enabled() const {
14421451}
14431452
14441453void CodeEdit::set_line_numbers_zero_padded (bool p_zero_padded) {
1445- p_zero_padded ? line_number_padding = " 0" : line_number_padding = " " ;
1454+ String new_line_number_padding = p_zero_padded ? " 0" : " " ;
1455+ if (line_number_padding == new_line_number_padding) {
1456+ return ;
1457+ }
1458+
1459+ line_number_padding = new_line_number_padding;
1460+ _clear_line_number_text_cache ();
14461461 queue_redraw ();
14471462}
14481463
@@ -1451,19 +1466,55 @@ bool CodeEdit::is_line_numbers_zero_padded() const {
14511466}
14521467
14531468void CodeEdit::_line_number_draw_callback (int p_line, int p_gutter, const Rect2 &p_region) {
1454- String fc = String::num (p_line + 1 ).lpad (line_number_digits, line_number_padding);
1455- if (is_localizing_numeral_system ()) {
1456- fc = TS->format_number (fc);
1457- }
1458- Ref<TextLine> tl;
1459- tl.instantiate ();
1460- tl->add_string (fc, theme_cache.font , theme_cache.font_size );
1461- int yofs = p_region.position .y + (get_line_height () - tl->get_size ().y ) / 2 ;
1469+ if (!Rect2 (Vector2 (0 , 0 ), get_size ()).intersects (p_region)) {
1470+ return ;
1471+ }
1472+
1473+ bool rtl = is_layout_rtl ();
1474+ HashMap<int , RID>::Iterator E = line_number_text_cache.find (p_line);
1475+ RID text_rid;
1476+ if (E) {
1477+ text_rid = E->value ;
1478+ } else {
1479+ String fc = String::num (p_line + 1 ).lpad (line_number_digits, line_number_padding);
1480+ if (is_localizing_numeral_system ()) {
1481+ fc = TS->format_number (fc);
1482+ }
1483+
1484+ text_rid = TS->create_shaped_text ();
1485+ if (theme_cache.font .is_valid ()) {
1486+ TS->shaped_text_add_string (text_rid, fc, theme_cache.font ->get_rids (), theme_cache.font_size , theme_cache.font ->get_opentype_features ());
1487+ }
1488+ line_number_text_cache.insert (p_line, text_rid);
1489+ }
1490+
1491+ Size2 text_size = TS->shaped_text_get_size (text_rid);
1492+ Point2 ofs = p_region.get_center () - text_size / 2 ;
1493+ ofs.y += TS->shaped_text_get_ascent (text_rid);
1494+
1495+ if (rtl) {
1496+ ofs.x = p_region.position .x ;
1497+ } else {
1498+ ofs.x = p_region.get_end ().x - text_size.width ;
1499+ }
1500+
14621501 Color number_color = get_line_gutter_item_color (p_line, line_number_gutter);
14631502 if (number_color == Color (1 , 1 , 1 )) {
14641503 number_color = theme_cache.line_number_color ;
14651504 }
1466- tl->draw (get_canvas_item (), Point2 (p_region.position .x , yofs), number_color);
1505+
1506+ TS->shaped_text_draw (text_rid, get_canvas_item (), ofs, -1 , -1 , number_color);
1507+ }
1508+
1509+ void CodeEdit::_clear_line_number_text_cache () {
1510+ for (const KeyValue<int , RID> &KV : line_number_text_cache) {
1511+ TS->free_rid (KV.value );
1512+ }
1513+ line_number_text_cache.clear ();
1514+ }
1515+
1516+ void CodeEdit::_update_line_number_gutter_width () {
1517+ set_gutter_width (line_number_gutter, (line_number_digits + 1 ) * theme_cache.font ->get_char_size (' 0' , theme_cache.font_size ).width );
14671518}
14681519
14691520/* Fold Gutter */
@@ -1983,12 +2034,18 @@ Point2 CodeEdit::get_delimiter_end_position(int p_line, int p_column) const {
19832034
19842035/* Code hint */
19852036void CodeEdit::set_code_hint (const String &p_hint) {
2037+ if (code_hint == p_hint) {
2038+ return ;
2039+ }
19862040 code_hint = p_hint;
19872041 code_hint_xpos = -0xFFFF ;
19882042 queue_redraw ();
19892043}
19902044
19912045void CodeEdit::set_code_hint_draw_below (bool p_below) {
2046+ if (code_hint_draw_below == p_below) {
2047+ return ;
2048+ }
19922049 code_hint_draw_below = p_below;
19932050 queue_redraw ();
19942051}
@@ -3609,16 +3666,13 @@ void CodeEdit::_text_changed() {
36093666 }
36103667
36113668 int lc = get_line_count ();
3612- line_number_digits = 1 ;
3613- while (lc /= 10 ) {
3614- line_number_digits++;
3615- }
3616-
3617- if (theme_cache.font .is_valid ()) {
3618- set_gutter_width (line_number_gutter, (line_number_digits + 1 ) * theme_cache.font ->get_char_size (' 0' , theme_cache.font_size ).width );
3669+ int new_line_number_digits = log10l (lc) + 1 ;
3670+ if (line_number_digits != new_line_number_digits) {
3671+ _clear_line_number_text_cache ();
36193672 }
3673+ line_number_digits = new_line_number_digits;
3674+ _update_line_number_gutter_width ();
36203675
3621- lc = get_line_count ();
36223676 List<int > breakpoints;
36233677 for (const KeyValue<int , bool > &E : breakpointed_lines) {
36243678 breakpoints.push_back (E.key );
@@ -3705,6 +3759,7 @@ CodeEdit::CodeEdit() {
37053759}
37063760
37073761CodeEdit::~CodeEdit () {
3762+ _clear_line_number_text_cache ();
37083763}
37093764
37103765// Return true if l should come before r
0 commit comments