Browse Source

Merge pull request #52860 from bruvzg/vis_chars

Rémi Verschelde 3 years ago
parent
commit
a24e870c71
2 changed files with 69 additions and 73 deletions
  1. 29 56
      scene/gui/label.cpp
  2. 40 17
      scene/gui/rich_text_label.cpp

+ 29 - 56
scene/gui/label.cpp

@@ -92,8 +92,12 @@ void Label::_shape() {
 		const Ref<Font> &font = get_theme_font(SNAME("font"));
 		int font_size = get_theme_font_size(SNAME("font_size"));
 		ERR_FAIL_COND(font.is_null());
-		TS->shaped_text_add_string(text_rid, (uppercase) ? xl_text.to_upper() : xl_text, font->get_rids(), font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
-		TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, xl_text));
+		String text = (uppercase) ? xl_text.to_upper() : xl_text;
+		if (visible_chars >= 0) {
+			text = text.substr(0, visible_chars);
+		}
+		TS->shaped_text_add_string(text_rid, text, font->get_rids(), font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
+		TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, text));
 		dirty = false;
 		lines_dirty = true;
 	}
@@ -258,6 +262,9 @@ void Label::_notification(int p_what) {
 			return; // Nothing new.
 		}
 		xl_text = new_text;
+		if (percent_visible < 1) {
+			visible_chars = get_total_character_count() * percent_visible;
+		}
 		dirty = true;
 
 		update();
@@ -342,24 +349,6 @@ void Label::_notification(int p_what) {
 			}
 		}
 
-		int visible_glyphs = -1;
-		int glyhps_drawn = 0;
-		if (percent_visible < 1) {
-			int total_glyphs = 0;
-			for (int i = lines_skipped; i < last_line; i++) {
-				const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(lines_rid[i]);
-				const TextServer::Glyph *glyphs = visual.ptr();
-				int gl_size = visual.size();
-				for (int j = 0; j < gl_size; j++) {
-					if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
-						total_glyphs++;
-					}
-				}
-			}
-
-			visible_glyphs = MIN(total_glyphs, visible_chars);
-		}
-
 		Vector2 ofs;
 		ofs.y = style->get_offset().y + vbegin;
 		for (int i = lines_skipped; i < last_line; i++) {
@@ -407,14 +396,6 @@ void Label::_notification(int p_what) {
 				// Draw main text.
 				for (int j = 0; j < gl_size; j++) {
 					for (int k = 0; k < glyphs[j].repeat; k++) {
-						if (visible_glyphs != -1) {
-							if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
-								if (glyhps_drawn >= visible_glyphs) {
-									return;
-								}
-							}
-						}
-
 						// Trim when necessary.
 						if (trim_data.trim_pos >= 0) {
 							if (rtl) {
@@ -431,7 +412,6 @@ void Label::_notification(int p_what) {
 						// Draw glyph outlines and shadow.
 						draw_glyph_outline(glyphs[j], ci, font_color, font_shadow_color, font_outline_color, shadow_outline_size, outline_size, offset, shadow_ofs);
 						offset.x += glyphs[j].advance;
-						glyhps_drawn++;
 					}
 				}
 				// Draw LTR ellipsis string when necessary.
@@ -462,14 +442,6 @@ void Label::_notification(int p_what) {
 			// Draw main text.
 			for (int j = 0; j < gl_size; j++) {
 				for (int k = 0; k < glyphs[j].repeat; k++) {
-					if (visible_glyphs != -1) {
-						if ((glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
-							if (glyhps_drawn >= visible_glyphs) {
-								return;
-							}
-						}
-					}
-
 					// Trim when necessary.
 					if (trim_data.trim_pos >= 0) {
 						if (rtl) {
@@ -486,7 +458,6 @@ void Label::_notification(int p_what) {
 					// Draw glyph outlines and shadow.
 					draw_glyph(glyphs[j], ci, font_color, ofs);
 					ofs.x += glyphs[j].advance;
-					glyhps_drawn++;
 				}
 			}
 			// Draw LTR ellipsis string when necessary.
@@ -709,16 +680,16 @@ String Label::get_text() const {
 }
 
 void Label::set_visible_characters(int p_amount) {
-	visible_chars = p_amount;
-	if (get_total_character_count() > 0) {
-		percent_visible = (float)p_amount / (float)get_total_character_count();
-	} else {
-		percent_visible = 1.0;
-	}
-	if (p_amount == -1) {
-		lines_dirty = true;
+	if (visible_chars != p_amount) {
+		visible_chars = p_amount;
+		if (get_total_character_count() > 0) {
+			percent_visible = (float)p_amount / (float)get_total_character_count();
+		} else {
+			percent_visible = 1.0;
+		}
+		dirty = true;
+		update();
 	}
-	update();
 }
 
 int Label::get_visible_characters() const {
@@ -726,15 +697,17 @@ int Label::get_visible_characters() const {
 }
 
 void Label::set_percent_visible(float p_percent) {
-	if (p_percent < 0 || p_percent >= 1) {
-		visible_chars = -1;
-		percent_visible = 1;
-		lines_dirty = true;
-	} else {
-		visible_chars = get_total_character_count() * p_percent;
-		percent_visible = p_percent;
+	if (percent_visible != p_percent) {
+		if (p_percent < 0 || p_percent >= 1) {
+			visible_chars = -1;
+			percent_visible = 1;
+		} else {
+			visible_chars = get_total_character_count() * p_percent;
+			percent_visible = p_percent;
+		}
+		dirty = true;
+		update();
 	}
-	update();
 }
 
 float Label::get_percent_visible() const {
@@ -889,7 +862,7 @@ void Label::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "is_clipping_text");
 	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");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
-	ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1", PROPERTY_USAGE_EDITOR), "set_visible_characters", "get_visible_characters");
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1"), "set_visible_characters", "get_visible_characters");
 	ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "percent_visible", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_percent_visible", "get_percent_visible");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "lines_skipped", PROPERTY_HINT_RANGE, "0,999,1"), "set_lines_skipped", "get_lines_skipped");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "max_lines_visible", PROPERTY_HINT_RANGE, "-1,999,1"), "set_max_lines_visible", "get_max_lines_visible");

+ 40 - 17
scene/gui/rich_text_label.cpp

@@ -399,8 +399,9 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
 	// Shape current paragraph.
 	String text;
 	Item *it_to = (p_line + 1 < p_frame->lines.size()) ? p_frame->lines[p_line + 1].from : nullptr;
+	int remaining_characters = visible_characters - l.char_offset;
 	for (Item *it = l.from; it && it != it_to; it = _get_next_item(it)) {
-		if (visible_characters >= 0 && l.char_offset + l.char_count > visible_characters) {
+		if (visible_characters >= 0 && remaining_characters <= 0) {
 			break;
 		}
 		switch (it->type) {
@@ -427,7 +428,8 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
 				}
 				l.text_buf->add_string("\n", font, font_size, Dictionary(), "");
 				text += "\n";
-				l.char_count += 1;
+				l.char_count++;
+				remaining_characters--;
 			} break;
 			case ITEM_TEXT: {
 				ItemText *t = (ItemText *)it;
@@ -442,9 +444,10 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
 				Dictionary font_ftr = _find_font_features(it);
 				String lang = _find_language(it);
 				String tx = t->text;
-				if (visible_characters >= 0 && l.char_offset + l.char_count + tx.length() > visible_characters) {
-					tx = tx.substr(0, l.char_offset + l.char_count + tx.length() - visible_characters);
+				if (visible_characters >= 0 && remaining_characters >= 0) {
+					tx = tx.substr(0, remaining_characters);
 				}
+				remaining_characters -= tx.length();
 
 				l.text_buf->add_string(tx, font, font_size, font_ftr, lang);
 				text += tx;
@@ -454,7 +457,8 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
 				ItemImage *img = (ItemImage *)it;
 				l.text_buf->add_object((uint64_t)it, img->image->get_size(), img->inline_align, 1);
 				text += String::chr(0xfffc);
-				l.char_count += 1;
+				l.char_count++;
+				remaining_characters--;
 			} break;
 			case ITEM_TABLE: {
 				ItemTable *table = static_cast<ItemTable *>(it);
@@ -483,6 +487,7 @@ void RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
 						int cell_ch = (char_offset - (l.char_offset + l.char_count));
 						l.char_count += cell_ch;
 						t_char_count += cell_ch;
+						remaining_characters -= cell_ch;
 
 						table->columns.write[column].min_width = MAX(table->columns[column].min_width, ceil(frame->lines[i].text_buf->get_size().x));
 						table->columns.write[column].max_width = MAX(table->columns[column].max_width, ceil(frame->lines[i].text_buf->get_non_wraped_size().x));
@@ -3855,7 +3860,12 @@ String RichTextLabel::get_parsed_text() const {
 	String text = "";
 	Item *it = main;
 	while (it) {
-		if (it->type == ITEM_TEXT) {
+		if (it->type == ITEM_DROPCAP) {
+			const ItemDropcap *dc = (ItemDropcap *)it;
+			if (dc != nullptr) {
+				text += dc->text;
+			}
+		} else if (it->type == ITEM_TEXT) {
 			ItemText *t = static_cast<ItemText *>(it);
 			text += t->text;
 		} else if (it->type == ITEM_NEWLINE) {
@@ -3926,7 +3936,6 @@ void RichTextLabel::set_percent_visible(float p_percent) {
 		if (p_percent < 0 || p_percent >= 1) {
 			visible_characters = -1;
 			percent_visible = 1;
-
 		} else {
 			visible_characters = get_total_character_count() * p_percent;
 			percent_visible = p_percent;
@@ -4160,16 +4169,20 @@ void RichTextLabel::_bind_methods() {
 }
 
 void RichTextLabel::set_visible_characters(int p_visible) {
-	visible_characters = p_visible;
-	if (p_visible == -1) {
-		percent_visible = 1;
-	} else {
-		int total_char_count = get_total_character_count();
-		if (total_char_count > 0) {
-			percent_visible = (float)p_visible / (float)total_char_count;
+	if (visible_characters != p_visible) {
+		visible_characters = p_visible;
+		if (p_visible == -1) {
+			percent_visible = 1;
+		} else {
+			int total_char_count = get_total_character_count();
+			if (total_char_count > 0) {
+				percent_visible = (float)p_visible / (float)total_char_count;
+			}
 		}
+		main->first_invalid_line = 0; //invalidate ALL
+		_validate_line_caches(main);
+		update();
 	}
-	update();
 }
 
 int RichTextLabel::get_visible_characters() const {
@@ -4177,9 +4190,19 @@ int RichTextLabel::get_visible_characters() const {
 }
 
 int RichTextLabel::get_total_character_count() const {
+	// Note: Do not use line buffer "char_count", it includes only visible characters.
 	int tc = 0;
-	for (int i = 0; i < current_frame->lines.size(); i++) {
-		tc += current_frame->lines[i].char_count;
+	Item *it = main;
+	while (it) {
+		if (it->type == ITEM_TEXT) {
+			ItemText *t = static_cast<ItemText *>(it);
+			tc += t->text.length();
+		} else if (it->type == ITEM_NEWLINE) {
+			tc++;
+		} else if (it->type == ITEM_IMAGE) {
+			tc++;
+		}
+		it = _get_next_item(it, true);
 	}
 
 	return tc;