1
0
Fork 0

Optimise TextEdit get height and width

This commit is contained in:
Paulb23 2021-08-27 20:05:05 +01:00
parent 90a35dac48
commit de009cb5ae
3 changed files with 133 additions and 47 deletions

View File

@ -158,7 +158,6 @@ void ScriptTextEditor::enable_editor() {
editor_enabled = true; editor_enabled = true;
_enable_code_editor(); _enable_code_editor();
_set_theme_for_script();
_validate_script(); _validate_script();
} }

View File

@ -37,6 +37,7 @@
#include "core/object/script_language.h" #include "core/object/script_language.h"
#include "core/os/keyboard.h" #include "core/os/keyboard.h"
#include "core/os/os.h" #include "core/os/os.h"
#include "core/string/string_builder.h"
#include "core/string/translation.h" #include "core/string/translation.h"
#include "scene/main/window.h" #include "scene/main/window.h"
@ -78,7 +79,11 @@ void TextEdit::Text::set_font_size(int p_font_size) {
} }
void TextEdit::Text::set_tab_size(int p_tab_size) { void TextEdit::Text::set_tab_size(int p_tab_size) {
if (tab_size == p_tab_size) {
return;
}
tab_size = p_tab_size; tab_size = p_tab_size;
tab_size_dirty = true;
} }
int TextEdit::Text::get_tab_size() const { int TextEdit::Text::get_tab_size() const {
@ -118,10 +123,8 @@ int TextEdit::Text::get_line_width(int p_line, int p_wrap_index) const {
return text[p_line].data_buf->get_size().x; return text[p_line].data_buf->get_size().x;
} }
int TextEdit::Text::get_line_height(int p_line, int p_wrap_index) const { int TextEdit::Text::get_line_height() const {
ERR_FAIL_INDEX_V(p_line, text.size(), 0); return line_height;
return text[p_line].data_buf->get_line_size(p_wrap_index).y;
} }
void TextEdit::Text::set_width(float p_width) { void TextEdit::Text::set_width(float p_width) {
@ -153,6 +156,36 @@ _FORCE_INLINE_ const String &TextEdit::Text::operator[](int p_line) const {
return text[p_line].data; return text[p_line].data;
} }
void TextEdit::Text::_calculate_line_height() {
int height = 0;
for (int i = 0; i < text.size(); i++) {
// Found another line with the same height...nothing to update.
if (text[i].height == line_height) {
height = line_height;
break;
}
height = MAX(height, text[i].height);
}
line_height = height;
}
void TextEdit::Text::_calculate_max_line_width() {
int width = 0;
for (int i = 0; i < text.size(); i++) {
if (is_hidden(i)) {
continue;
}
// Found another line with the same width...nothing to update.
if (text[i].width == max_width) {
width = max_width;
break;
}
width = MAX(width, text[i].width);
}
max_width = width;
}
void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_ime_text, const Vector<Vector2i> &p_bidi_override) { void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_ime_text, const Vector<Vector2i> &p_bidi_override) {
ERR_FAIL_INDEX(p_line, text.size()); ERR_FAIL_INDEX(p_line, text.size());
@ -182,17 +215,54 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_
tabs.push_back(font->get_char_size(' ', 0, font_size).width * tab_size); tabs.push_back(font->get_char_size(' ', 0, font_size).width * tab_size);
text.write[p_line].data_buf->tab_align(tabs); text.write[p_line].data_buf->tab_align(tabs);
} }
// Update height.
const int old_height = text.write[p_line].height;
const int wrap_amount = get_line_wrap_amount(p_line);
int height = font->get_height(font_size);
for (int i = 0; i <= wrap_amount; i++) {
height = MAX(height, text[p_line].data_buf->get_line_size(i).y);
}
text.write[p_line].height = height;
// If this line has shrunk, this may no longer the the tallest line.
if (old_height == line_height && height < line_height) {
_calculate_line_height();
} else {
line_height = MAX(height, line_height);
}
// Update width.
const int old_width = text.write[p_line].width;
int width = get_line_width(p_line);
text.write[p_line].width = width;
// If this line has shrunk, this may no longer the the longest line.
if (old_width == max_width && width < max_width) {
_calculate_max_line_width();
} else if (!is_hidden(p_line)) {
max_width = MAX(width, max_width);
}
} }
void TextEdit::Text::invalidate_all_lines() { void TextEdit::Text::invalidate_all_lines() {
for (int i = 0; i < text.size(); i++) { for (int i = 0; i < text.size(); i++) {
text.write[i].data_buf->set_width(width); text.write[i].data_buf->set_width(width);
if (tab_size > 0) { if (tab_size_dirty) {
Vector<float> tabs; if (tab_size > 0) {
tabs.push_back(font->get_char_size(' ', 0, font_size).width * tab_size); Vector<float> tabs;
text.write[i].data_buf->tab_align(tabs); tabs.push_back(font->get_char_size(' ', 0, font_size).width * tab_size);
text.write[i].data_buf->tab_align(tabs);
}
// Tabs have changes, force width update.
text.write[i].width = get_line_width(i);
} }
} }
if (tab_size_dirty) {
_calculate_max_line_width();
tab_size_dirty = false;
}
} }
void TextEdit::Text::invalidate_all() { void TextEdit::Text::invalidate_all() {
@ -211,16 +281,8 @@ void TextEdit::Text::clear() {
insert(0, "", Vector<Vector2i>()); insert(0, "", Vector<Vector2i>());
} }
int TextEdit::Text::get_max_width(bool p_exclude_hidden) const { int TextEdit::Text::get_max_width() const {
// Quite some work, but should be fast enough. return max_width;
int max = 0;
for (int i = 0; i < text.size(); i++) {
if (!p_exclude_hidden || !is_hidden(i)) {
max = MAX(max, get_line_width(i));
}
}
return max;
} }
void TextEdit::Text::set(int p_line, const String &p_text, const Vector<Vector2i> &p_bidi_override) { void TextEdit::Text::set(int p_line, const String &p_text, const Vector<Vector2i> &p_bidi_override) {
@ -243,7 +305,20 @@ void TextEdit::Text::insert(int p_at, const String &p_text, const Vector<Vector2
} }
void TextEdit::Text::remove(int p_at) { void TextEdit::Text::remove(int p_at) {
int height = text[p_at].height;
int width = text[p_at].width;
text.remove(p_at); text.remove(p_at);
// If this is the tallest line, we need to get the next tallest.
if (height == line_height) {
_calculate_line_height();
}
// If this is the longest line, we need to get the next longest.
if (width == max_width) {
_calculate_max_line_width();
}
} }
void TextEdit::Text::add_gutter(int p_at) { void TextEdit::Text::add_gutter(int p_at) {
@ -293,7 +368,7 @@ void TextEdit::_notification(int p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: { case NOTIFICATION_VISIBILITY_CHANGED: {
if (is_visible()) { if (is_visible()) {
call_deferred(SNAME("_update_scrollbars")); call_deferred(SNAME("_update_scrollbars"));
call_deferred(SNAME("_update_wrap_at")); call_deferred(SNAME("_update_wrap_at_column"));
} }
} break; } break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
@ -632,8 +707,9 @@ void TextEdit::_notification(int p_what) {
int characters = 0; int characters = 0;
int tabs = 0; int tabs = 0;
for (int j = 0; j < str.length(); j++) { for (int j = 0; j < str.length(); j++) {
if (color_map.has(last_wrap_column + j)) { const Variant *color_data = color_map.getptr(last_wrap_column + j);
current_color = color_map[last_wrap_column + j].get("color"); if (color_data != nullptr) {
current_color = (color_data->operator Dictionary()).get("color", font_color);
if (!editable) { if (!editable) {
current_color.a = font_readonly_color.a; current_color.a = font_readonly_color.a;
} }
@ -1011,8 +1087,9 @@ 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++) {
if (color_map.has(glyphs[j].start)) { const Variant *color_data = color_map.getptr(glyphs[j].start);
current_color = color_map[glyphs[j].start].get("color"); if (color_data != nullptr) {
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) {
current_color.a = font_readonly_color.a; current_color.a = font_readonly_color.a;
} }
@ -2532,15 +2609,15 @@ void TextEdit::set_text(const String &p_text) {
} }
String TextEdit::get_text() const { String TextEdit::get_text() const {
String longthing; StringBuilder ret_text;
int len = text.size(); const int text_size = text.size();
for (int i = 0; i < len; i++) { for (int i = 0; i < text_size; i++) {
longthing += text[i]; ret_text += text[i];
if (i != len - 1) { if (i != text_size - 1) {
longthing += "\n"; ret_text += "\n";
} }
} }
return longthing; return ret_text.as_string();
} }
int TextEdit::get_line_count() const { int TextEdit::get_line_count() const {
@ -2576,13 +2653,7 @@ int TextEdit::get_line_width(int p_line, int p_wrap_index) const {
} }
int TextEdit::get_line_height() const { int TextEdit::get_line_height() const {
int height = font->get_height(font_size); return text.get_line_height() + line_spacing;
for (int i = 0; i < text.size(); i++) {
for (int j = 0; j <= text.get_line_wrap_amount(i); j++) {
height = MAX(height, text.get_line_height(i, j));
}
}
return height + line_spacing;
} }
int TextEdit::get_indent_level(int p_line) const { int TextEdit::get_indent_level(int p_line) const {
@ -4135,6 +4206,9 @@ TextEdit::GutterType TextEdit::get_gutter_type(int p_gutter) const {
void TextEdit::set_gutter_width(int p_gutter, int p_width) { void TextEdit::set_gutter_width(int p_gutter, int p_width) {
ERR_FAIL_INDEX(p_gutter, gutters.size()); ERR_FAIL_INDEX(p_gutter, gutters.size());
if (gutters[p_gutter].width == p_width) {
return;
}
gutters.write[p_gutter].width = p_width; gutters.write[p_gutter].width = p_width;
_update_gutter_width(); _update_gutter_width();
} }
@ -4150,6 +4224,9 @@ int TextEdit::get_total_gutter_width() const {
void TextEdit::set_gutter_draw(int p_gutter, bool p_draw) { void TextEdit::set_gutter_draw(int p_gutter, bool p_draw) {
ERR_FAIL_INDEX(p_gutter, gutters.size()); ERR_FAIL_INDEX(p_gutter, gutters.size());
if (gutters[p_gutter].draw == p_draw) {
return;
}
gutters.write[p_gutter].draw = p_draw; gutters.write[p_gutter].draw = p_draw;
_update_gutter_width(); _update_gutter_width();
} }
@ -5442,7 +5519,7 @@ void TextEdit::_update_scrollbars() {
} }
int visible_width = size.width - style_normal->get_minimum_size().width; int visible_width = size.width - style_normal->get_minimum_size().width;
int total_width = text.get_max_width(true) + vmin.x + gutters_width + gutter_padding; int total_width = text.get_max_width() + vmin.x + gutters_width + gutter_padding;
if (draw_minimap) { if (draw_minimap) {
total_width += minimap_width; total_width += minimap_width;
@ -5867,8 +5944,6 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
text.set_hidden(p_line, false); text.set_hidden(p_line, false);
} }
text.invalidate_cache(p_line);
r_end_line = p_line + substrings.size() - 1; r_end_line = p_line + substrings.size() - 1;
r_end_column = text[r_end_line].length() - postinsert_text.length(); r_end_column = text[r_end_line].length() - postinsert_text.length();
@ -5925,8 +6000,6 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
} }
text.set(p_from_line, pre_text + post_text, structured_text_parser(st_parser, st_args, pre_text + post_text)); text.set(p_from_line, pre_text + post_text, structured_text_parser(st_parser, st_args, pre_text + post_text));
text.invalidate_cache(p_from_line);
if (!text_changed_dirty && !setting_text) { if (!text_changed_dirty && !setting_text) {
if (is_inside_tree()) { if (is_inside_tree()) {
MessageQueue::get_singleton()->push_call(this, "_text_changed_emit"); MessageQueue::get_singleton()->push_call(this, "_text_changed_emit");
@ -5943,7 +6016,6 @@ TextEdit::TextEdit() {
set_default_cursor_shape(CURSOR_IBEAM); set_default_cursor_shape(CURSOR_IBEAM);
text.set_tab_size(text.get_tab_size()); text.set_tab_size(text.get_tab_size());
text.clear();
h_scroll = memnew(HScrollBar); h_scroll = memnew(HScrollBar);
v_scroll = memnew(VScrollBar); v_scroll = memnew(VScrollBar);

View File

@ -144,6 +144,8 @@ private:
Color background_color = Color(0, 0, 0, 0); Color background_color = Color(0, 0, 0, 0);
bool hidden = false; bool hidden = false;
int height = 0;
int width = 0;
Line() { Line() {
data_buf.instantiate(); data_buf.instantiate();
@ -152,6 +154,7 @@ private:
private: private:
bool is_dirty = false; bool is_dirty = false;
bool tab_size_dirty = false;
mutable Vector<Line> text; mutable Vector<Line> text;
Ref<Font> font; Ref<Font> font;
@ -162,11 +165,16 @@ private:
TextServer::Direction direction = TextServer::DIRECTION_AUTO; TextServer::Direction direction = TextServer::DIRECTION_AUTO;
bool draw_control_chars = false; bool draw_control_chars = false;
int line_height = -1;
int max_width = -1;
int width = -1; int width = -1;
int tab_size = 4; int tab_size = 4;
int gutter_count = 0; int gutter_count = 0;
void _calculate_line_height();
void _calculate_max_line_width();
public: public:
void set_tab_size(int p_tab_size); void set_tab_size(int p_tab_size);
int get_tab_size() const; int get_tab_size() const;
@ -176,9 +184,9 @@ private:
void set_direction_and_language(TextServer::Direction p_direction, const String &p_language); void set_direction_and_language(TextServer::Direction p_direction, const String &p_language);
void set_draw_control_chars(bool p_draw_control_chars); void set_draw_control_chars(bool p_draw_control_chars);
int get_line_height(int p_line, int p_wrap_index) const; int get_line_height() const;
int get_line_width(int p_line, int p_wrap_index = -1) const; int get_line_width(int p_line, int p_wrap_index = -1) const;
int get_max_width(bool p_exclude_hidden = false) const; int get_max_width() const;
void set_width(float p_width); void set_width(float p_width);
int get_line_wrap_amount(int p_line) const; int get_line_wrap_amount(int p_line) const;
@ -187,7 +195,14 @@ private:
const Ref<TextParagraph> get_line_data(int p_line) const; const Ref<TextParagraph> get_line_data(int p_line) const;
void set(int p_line, const String &p_text, const Vector<Vector2i> &p_bidi_override); void set(int p_line, const String &p_text, const Vector<Vector2i> &p_bidi_override);
void set_hidden(int p_line, bool p_hidden) { text.write[p_line].hidden = p_hidden; } void set_hidden(int p_line, bool p_hidden) {
text.write[p_line].hidden = p_hidden;
if (!p_hidden && text[p_line].width > max_width) {
max_width = text[p_line].width;
} else if (p_hidden && text[p_line].width == max_width) {
_calculate_max_line_width();
}
}
bool is_hidden(int p_line) const { return text[p_line].hidden; } bool is_hidden(int p_line) const { return text[p_line].hidden; }
void insert(int p_at, const String &p_text, const Vector<Vector2i> &p_bidi_override); void insert(int p_at, const String &p_text, const Vector<Vector2i> &p_bidi_override);
void remove(int p_at); void remove(int p_at);