|
@@ -922,7 +922,7 @@ void TextEdit::_notification(int p_what) {
|
|
int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0);
|
|
int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0);
|
|
draw_amount += times_line_wraps(first_visible_line + 1);
|
|
draw_amount += times_line_wraps(first_visible_line + 1);
|
|
|
|
|
|
- // minimap
|
|
|
|
|
|
+ // Draw minimap.
|
|
if (draw_minimap) {
|
|
if (draw_minimap) {
|
|
int minimap_visible_lines = _get_minimap_visible_rows();
|
|
int minimap_visible_lines = _get_minimap_visible_rows();
|
|
int minimap_line_height = (minimap_char_size.y + minimap_line_spacing);
|
|
int minimap_line_height = (minimap_char_size.y + minimap_line_spacing);
|
|
@@ -1091,7 +1091,8 @@ void TextEdit::_notification(int p_what) {
|
|
bottom_limit_y -= cache.style_normal->get_margin(MARGIN_TOP);
|
|
bottom_limit_y -= cache.style_normal->get_margin(MARGIN_TOP);
|
|
}
|
|
}
|
|
|
|
|
|
- // draw main text
|
|
|
|
|
|
+ // Draw main text.
|
|
|
|
+ line_drawing_cache.clear();
|
|
int line = first_visible_line;
|
|
int line = first_visible_line;
|
|
for (int i = 0; i < draw_amount; i++) {
|
|
for (int i = 0; i < draw_amount; i++) {
|
|
line++;
|
|
line++;
|
|
@@ -1112,6 +1113,7 @@ void TextEdit::_notification(int p_what) {
|
|
}
|
|
}
|
|
|
|
|
|
const String &fullstr = text[line];
|
|
const String &fullstr = text[line];
|
|
|
|
+ LineDrawingCache cache_entry;
|
|
|
|
|
|
Map<int, HighlighterInfo> color_map;
|
|
Map<int, HighlighterInfo> color_map;
|
|
if (syntax_coloring) {
|
|
if (syntax_coloring) {
|
|
@@ -1125,6 +1127,7 @@ void TextEdit::_notification(int p_what) {
|
|
Vector<String> wrap_rows = get_wrap_rows_text(line);
|
|
Vector<String> wrap_rows = get_wrap_rows_text(line);
|
|
int line_wrap_amount = times_line_wraps(line);
|
|
int line_wrap_amount = times_line_wraps(line);
|
|
int last_wrap_column = 0;
|
|
int last_wrap_column = 0;
|
|
|
|
+ int wrap_column_offset = 0;
|
|
|
|
|
|
for (int line_wrap_index = 0; line_wrap_index < line_wrap_amount + 1; line_wrap_index++) {
|
|
for (int line_wrap_index = 0; line_wrap_index < line_wrap_amount + 1; line_wrap_index++) {
|
|
if (line_wrap_index != 0) {
|
|
if (line_wrap_index != 0) {
|
|
@@ -1219,6 +1222,8 @@ void TextEdit::_notification(int p_what) {
|
|
if (line_wrap_index == 0) {
|
|
if (line_wrap_index == 0) {
|
|
// Only do these if we are on the first wrapped part of a line.
|
|
// Only do these if we are on the first wrapped part of a line.
|
|
|
|
|
|
|
|
+ cache_entry.y_offset = ofs_y;
|
|
|
|
+
|
|
if (text.is_breakpoint(line) && !draw_breakpoint_gutter) {
|
|
if (text.is_breakpoint(line) && !draw_breakpoint_gutter) {
|
|
#ifdef TOOLS_ENABLED
|
|
#ifdef TOOLS_ENABLED
|
|
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color);
|
|
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg + ofs_x, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color);
|
|
@@ -1319,6 +1324,9 @@ void TextEdit::_notification(int p_what) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ int first_visible_char = str.length();
|
|
|
|
+ int last_visible_char = 0;
|
|
|
|
+
|
|
// Loop through characters in one line.
|
|
// Loop through characters in one line.
|
|
int j = 0;
|
|
int j = 0;
|
|
for (; j < str.length(); j++) {
|
|
for (; j < str.length(); j++) {
|
|
@@ -1542,6 +1550,13 @@ void TextEdit::_notification(int p_what) {
|
|
int yofs = (get_row_height() - cache.space_icon->get_height()) / 2;
|
|
int yofs = (get_row_height() - cache.space_icon->get_height()) / 2;
|
|
cache.space_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_color_selected : color);
|
|
cache.space_icon->draw(ci, Point2(char_ofs + char_margin + ofs_x, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_color_selected : color);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (first_visible_char > j) {
|
|
|
|
+ first_visible_char = j;
|
|
|
|
+ }
|
|
|
|
+ if (last_visible_char < j) {
|
|
|
|
+ last_visible_char = j;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
char_ofs += char_w;
|
|
char_ofs += char_w;
|
|
@@ -1615,7 +1630,14 @@ void TextEdit::_notification(int p_what) {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ cache_entry.first_visible_char.push_back(wrap_column_offset + first_visible_char);
|
|
|
|
+ cache_entry.last_visible_char.push_back(wrap_column_offset + last_visible_char);
|
|
|
|
+
|
|
|
|
+ wrap_column_offset += str.length();
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ line_drawing_cache[line] = cache_entry;
|
|
}
|
|
}
|
|
|
|
|
|
bool completion_below = false;
|
|
bool completion_below = false;
|
|
@@ -4782,6 +4804,57 @@ int TextEdit::get_row_height() const {
|
|
return cache.font->get_height() + cache.line_spacing;
|
|
return cache.font->get_height() + cache.line_spacing;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/* Line and character position. */
|
|
|
|
+Point2 TextEdit::get_pos_at_line_column(int p_line, int p_column) const {
|
|
|
|
+ Rect2i rect = get_rect_at_line_column(p_line, p_column);
|
|
|
|
+ return rect.position + Vector2i(0, get_line_height());
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+Rect2 TextEdit::get_rect_at_line_column(int p_line, int p_column) const {
|
|
|
|
+ ERR_FAIL_INDEX_V(p_line, text.size(), Rect2i(-1, -1, 0, 0));
|
|
|
|
+ ERR_FAIL_COND_V(p_column < 0, Rect2i(-1, -1, 0, 0));
|
|
|
|
+ ERR_FAIL_COND_V(p_column > text[p_line].length(), Rect2i(-1, -1, 0, 0));
|
|
|
|
+
|
|
|
|
+ if (line_drawing_cache.size() == 0 || !line_drawing_cache.has(p_line)) {
|
|
|
|
+ // Line is not in the cache, which means it's outside of the viewing area.
|
|
|
|
+ return Rect2i(-1, -1, 0, 0);
|
|
|
|
+ }
|
|
|
|
+ LineDrawingCache cache_entry = line_drawing_cache[p_line];
|
|
|
|
+
|
|
|
|
+ int wrap_index = get_line_wrap_index_at_col(p_line, p_column);
|
|
|
|
+ if (wrap_index >= cache_entry.first_visible_char.size()) {
|
|
|
|
+ // Line seems to be wrapped beyond the viewable area.
|
|
|
|
+ return Rect2i(-1, -1, 0, 0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int first_visible_char = cache_entry.first_visible_char[wrap_index];
|
|
|
|
+ int last_visible_char = cache_entry.last_visible_char[wrap_index];
|
|
|
|
+ if (p_column < first_visible_char || p_column > last_visible_char) {
|
|
|
|
+ // Character is outside of the viewing area, no point calculating its position.
|
|
|
|
+ return Rect2i(-1, -1, 0, 0);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ Point2i pos, size;
|
|
|
|
+ pos.y = cache_entry.y_offset + get_line_height() * wrap_index;
|
|
|
|
+ pos.x = get_total_gutter_width() + cache.style_normal->get_margin(MARGIN_LEFT) - get_h_scroll();
|
|
|
|
+
|
|
|
|
+ int start_x = get_column_x_offset_for_line(p_column, p_line);
|
|
|
|
+ pos.x += start_x;
|
|
|
|
+
|
|
|
|
+ String line = text[p_line];
|
|
|
|
+ size.x = cache.font->get_char_size(line[p_column]).width;
|
|
|
|
+ size.y = get_line_height();
|
|
|
|
+
|
|
|
|
+ return Rect2i(pos, size);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+Point2 TextEdit::get_line_column_at_pos(const Point2 &p_pos) const {
|
|
|
|
+ int row, col;
|
|
|
|
+ _get_mouse_pos(p_pos, row, col);
|
|
|
|
+
|
|
|
|
+ return Point2i(col, row);
|
|
|
|
+}
|
|
|
|
+
|
|
int TextEdit::get_char_pos_for_line(int p_px, int p_line, int p_wrap_index) const {
|
|
int TextEdit::get_char_pos_for_line(int p_px, int p_line, int p_wrap_index) const {
|
|
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
|
|
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
|
|
|
|
|
|
@@ -6953,6 +7026,10 @@ int TextEdit::get_info_gutter_width() const {
|
|
return info_gutter_width;
|
|
return info_gutter_width;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+int TextEdit::get_total_gutter_width() const {
|
|
|
|
+ return cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width + cache.info_gutter_width;
|
|
|
|
+}
|
|
|
|
+
|
|
void TextEdit::set_draw_minimap(bool p_draw) {
|
|
void TextEdit::set_draw_minimap(bool p_draw) {
|
|
draw_minimap = p_draw;
|
|
draw_minimap = p_draw;
|
|
update();
|
|
update();
|
|
@@ -7080,6 +7157,30 @@ PopupMenu *TextEdit::get_menu() const {
|
|
return menu;
|
|
return menu;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+int TextEdit::get_line_width(int p_line, int p_wrap_index) const {
|
|
|
|
+ ERR_FAIL_INDEX_V(p_line, text.size(), 0);
|
|
|
|
+
|
|
|
|
+ if (p_wrap_index >= 0 && line_wraps(p_line)) {
|
|
|
|
+ Vector<String> rows = get_wrap_rows_text(p_line);
|
|
|
|
+ ERR_FAIL_INDEX_V(p_wrap_index, rows.size(), 0);
|
|
|
|
+
|
|
|
|
+ int w = 0;
|
|
|
|
+ int len = rows[p_wrap_index].length();
|
|
|
|
+ const CharType *str = rows[p_wrap_index].c_str();
|
|
|
|
+ for (int i = 0; i < len; i++) {
|
|
|
|
+ w += text.get_char_width(str[i], str[i + 1], w);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return w;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return text.get_line_width(p_line);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int TextEdit::get_line_height() const {
|
|
|
|
+ return get_row_height();
|
|
|
|
+}
|
|
|
|
+
|
|
void TextEdit::_bind_methods() {
|
|
void TextEdit::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("_gui_input"), &TextEdit::_gui_input);
|
|
ClassDB::bind_method(D_METHOD("_gui_input"), &TextEdit::_gui_input);
|
|
ClassDB::bind_method(D_METHOD("_scroll_moved"), &TextEdit::_scroll_moved);
|
|
ClassDB::bind_method(D_METHOD("_scroll_moved"), &TextEdit::_scroll_moved);
|
|
@@ -7110,6 +7211,13 @@ void TextEdit::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("get_text"), &TextEdit::get_text);
|
|
ClassDB::bind_method(D_METHOD("get_text"), &TextEdit::get_text);
|
|
ClassDB::bind_method(D_METHOD("get_line", "line"), &TextEdit::get_line);
|
|
ClassDB::bind_method(D_METHOD("get_line", "line"), &TextEdit::get_line);
|
|
ClassDB::bind_method(D_METHOD("set_line", "line", "new_text"), &TextEdit::set_line);
|
|
ClassDB::bind_method(D_METHOD("set_line", "line", "new_text"), &TextEdit::set_line);
|
|
|
|
+ ClassDB::bind_method(D_METHOD("get_line_wrapped_text", "line"), &TextEdit::get_wrap_rows_text);
|
|
|
|
+
|
|
|
|
+ ClassDB::bind_method(D_METHOD("get_line_width", "line", "wrap_index"), &TextEdit::get_line_width, DEFVAL(-1));
|
|
|
|
+ ClassDB::bind_method(D_METHOD("get_line_height"), &TextEdit::get_line_height);
|
|
|
|
+
|
|
|
|
+ ClassDB::bind_method(D_METHOD("is_line_wrapped", "line"), &TextEdit::line_wraps);
|
|
|
|
+ ClassDB::bind_method(D_METHOD("get_line_wrap_count", "line"), &TextEdit::times_line_wraps);
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("center_viewport_to_cursor"), &TextEdit::center_viewport_to_cursor);
|
|
ClassDB::bind_method(D_METHOD("center_viewport_to_cursor"), &TextEdit::center_viewport_to_cursor);
|
|
ClassDB::bind_method(D_METHOD("cursor_set_column", "column", "adjust_viewport"), &TextEdit::cursor_set_column, DEFVAL(true));
|
|
ClassDB::bind_method(D_METHOD("cursor_set_column", "column", "adjust_viewport"), &TextEdit::cursor_set_column, DEFVAL(true));
|
|
@@ -7127,6 +7235,11 @@ void TextEdit::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("set_right_click_moves_caret", "enable"), &TextEdit::set_right_click_moves_caret);
|
|
ClassDB::bind_method(D_METHOD("set_right_click_moves_caret", "enable"), &TextEdit::set_right_click_moves_caret);
|
|
ClassDB::bind_method(D_METHOD("is_right_click_moving_caret"), &TextEdit::is_right_click_moving_caret);
|
|
ClassDB::bind_method(D_METHOD("is_right_click_moving_caret"), &TextEdit::is_right_click_moving_caret);
|
|
|
|
|
|
|
|
+ /* Line and character position. */
|
|
|
|
+ ClassDB::bind_method(D_METHOD("get_pos_at_line_column", "line", "column"), &TextEdit::get_pos_at_line_column);
|
|
|
|
+ ClassDB::bind_method(D_METHOD("get_rect_at_line_column", "line", "column"), &TextEdit::get_rect_at_line_column);
|
|
|
|
+ ClassDB::bind_method(D_METHOD("get_line_column_at_pos", "position"), &TextEdit::get_line_column_at_pos);
|
|
|
|
+
|
|
ClassDB::bind_method(D_METHOD("set_readonly", "enable"), &TextEdit::set_readonly);
|
|
ClassDB::bind_method(D_METHOD("set_readonly", "enable"), &TextEdit::set_readonly);
|
|
ClassDB::bind_method(D_METHOD("is_readonly"), &TextEdit::is_readonly);
|
|
ClassDB::bind_method(D_METHOD("is_readonly"), &TextEdit::is_readonly);
|
|
|
|
|
|
@@ -7182,6 +7295,7 @@ void TextEdit::_bind_methods() {
|
|
ClassDB::bind_method(D_METHOD("is_breakpoint_gutter_enabled"), &TextEdit::is_breakpoint_gutter_enabled);
|
|
ClassDB::bind_method(D_METHOD("is_breakpoint_gutter_enabled"), &TextEdit::is_breakpoint_gutter_enabled);
|
|
ClassDB::bind_method(D_METHOD("set_draw_fold_gutter"), &TextEdit::set_draw_fold_gutter);
|
|
ClassDB::bind_method(D_METHOD("set_draw_fold_gutter"), &TextEdit::set_draw_fold_gutter);
|
|
ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &TextEdit::is_drawing_fold_gutter);
|
|
ClassDB::bind_method(D_METHOD("is_drawing_fold_gutter"), &TextEdit::is_drawing_fold_gutter);
|
|
|
|
+ ClassDB::bind_method(D_METHOD("get_total_gutter_width"), &TextEdit::get_total_gutter_width);
|
|
|
|
|
|
ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled);
|
|
ClassDB::bind_method(D_METHOD("set_hiding_enabled", "enable"), &TextEdit::set_hiding_enabled);
|
|
ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled);
|
|
ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled);
|