summaryrefslogtreecommitdiff
path: root/scene/gui/text_edit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui/text_edit.cpp')
-rw-r--r--scene/gui/text_edit.cpp156
1 files changed, 124 insertions, 32 deletions
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 7a9daea73e..2d55c077f1 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -36,6 +36,10 @@
#include "project_settings.h"
#include "scene/main/viewport.h"
+#ifdef TOOLS_ENABLED
+#include "editor/editor_scale.h"
+#endif
+
#define TAB_PIXELS
static bool _is_text_char(CharType c) {
@@ -424,22 +428,22 @@ void TextEdit::_notification(int p_what) {
draw_caret = false;
update();
} break;
- case NOTIFICATION_FIXED_PROCESS: {
+ case NOTIFICATION_PHYSICS_PROCESS: {
if (scrolling && v_scroll->get_value() != target_v_scroll) {
double target_y = target_v_scroll - v_scroll->get_value();
double dist = sqrt(target_y * target_y);
- double vel = ((target_y / dist) * v_scroll_speed) * get_fixed_process_delta_time();
+ double vel = ((target_y / dist) * v_scroll_speed) * get_physics_process_delta_time();
- if (vel >= dist) {
+ if (Math::abs(vel) >= dist) {
v_scroll->set_value(target_v_scroll);
scrolling = false;
- set_fixed_process(false);
+ set_physics_process(false);
} else {
v_scroll->set_value(v_scroll->get_value() + vel);
}
} else {
scrolling = false;
- set_fixed_process(false);
+ set_physics_process(false);
}
} break;
case NOTIFICATION_DRAW: {
@@ -497,8 +501,7 @@ void TextEdit::_notification(int p_what) {
if (cache.background_color.a > 0.01) {
- Point2i ofs = Point2i(cache.style_normal->get_offset()) / 2.0;
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(ofs, get_size() - cache.style_normal->get_minimum_size() + ofs), cache.background_color);
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(), get_size()), cache.background_color);
}
//compute actual region to start (may be inside say, a comment).
//slow in very large documments :( but ok for source!
@@ -729,13 +732,25 @@ void TextEdit::_notification(int p_what) {
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.mark_color);
}
- if (text.is_breakpoint(line)) {
+ if (str.length() == 0) {
+ // draw line background if empty as we won't loop at at all
+ if (line == cursor.line && highlight_current_line) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_end, get_row_height()), cache.current_line_color);
+ }
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color);
+ // give visual indication of empty selected line
+ if (selection.active && line >= selection.from_line && line <= selection.to_line) {
+ int char_w = cache.font->get_char_size(' ').width;
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg, ofs_y, char_w, get_row_height()), cache.selection_color);
+ }
}
- if (line == cursor.line) {
- VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, xmargin_end, get_row_height()), cache.current_line_color);
+ if (text.is_breakpoint(line) && !draw_breakpoint_gutter) {
+#ifdef TOOLS_ENABLED
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg, ofs_y + get_row_height() - EDSCALE, xmargin_end - xmargin_beg, EDSCALE), cache.breakpoint_color);
+#else
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(xmargin_beg, ofs_y, xmargin_end - xmargin_beg, get_row_height()), cache.breakpoint_color);
+#endif
}
// draw breakpoint marker
@@ -758,6 +773,7 @@ void TextEdit::_notification(int p_what) {
cache.font->draw(ci, Point2(cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width, ofs_y + cache.font->get_ascent()), fc, cache.line_number_color);
}
+ //loop through charcters in one line
for (int j = 0; j < str.length(); j++) {
//look for keyword
@@ -946,10 +962,25 @@ void TextEdit::_notification(int p_what) {
}
}
+ //current line highlighting
bool in_selection = (selection.active && line >= selection.from_line && line <= selection.to_line && (line > selection.from_line || j >= selection.from_column) && (line < selection.to_line || j < selection.to_column));
+ if (line == cursor.line && highlight_current_line) {
+ // if its the first char draw behind line numbers
+ if (j == 0) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(0, ofs_y, (char_ofs + char_margin), get_row_height()), cache.current_line_color);
+ }
+ // if its the last char draw to end of the line
+ if (j == str.length() - 1) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(char_ofs + char_margin + char_w, ofs_y, xmargin_end - (char_ofs + char_margin + char_w), get_row_height()), cache.current_line_color);
+ }
+ // actual text
+ if (!in_selection) {
+ VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, get_row_height())), cache.current_line_color);
+ }
+ }
+
if (in_selection) {
- //inside selection!
VisualServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2i(char_ofs + char_margin, ofs_y), Size2i(char_w, get_row_height())), cache.selection_color);
}
@@ -992,7 +1023,7 @@ void TextEdit::_notification(int p_what) {
if (brace_open_mismatch)
color = cache.brace_mismatch_color;
- cache.font->draw_char(ci, Point2i(char_ofs + char_margin, ofs_y + ascent), '_', str[j + 1], in_selection ? cache.font_selected_color : color);
+ cache.font->draw_char(ci, Point2i(char_ofs + char_margin, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
}
if (
@@ -1001,7 +1032,7 @@ void TextEdit::_notification(int p_what) {
if (brace_close_mismatch)
color = cache.brace_mismatch_color;
- cache.font->draw_char(ci, Point2i(char_ofs + char_margin, ofs_y + ascent), '_', str[j + 1], in_selection ? cache.font_selected_color : color);
+ cache.font->draw_char(ci, Point2i(char_ofs + char_margin, ofs_y + ascent), '_', str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
}
}
@@ -1060,15 +1091,15 @@ void TextEdit::_notification(int p_what) {
}
if (str[j] >= 32) {
- int w = cache.font->draw_char(ci, Point2i(char_ofs + char_margin, ofs_y + ascent), str[j], str[j + 1], in_selection ? cache.font_selected_color : color);
+ int w = cache.font->draw_char(ci, Point2i(char_ofs + char_margin, ofs_y + ascent), str[j], str[j + 1], in_selection && override_selected_font_color ? cache.font_selected_color : color);
if (underlined) {
- draw_rect(Rect2(char_ofs + char_margin, ofs_y + ascent + 2, w, 1), in_selection ? cache.font_selected_color : color);
+ draw_rect(Rect2(char_ofs + char_margin, ofs_y + ascent + 2, w, 1), in_selection && override_selected_font_color ? cache.font_selected_color : color);
}
}
else if (draw_tabs && str[j] == '\t') {
int yofs = (get_row_height() - cache.tab_icon->get_height()) / 2;
- cache.tab_icon->draw(ci, Point2(char_ofs + char_margin, ofs_y + yofs), in_selection ? cache.font_selected_color : color);
+ cache.tab_icon->draw(ci, Point2(char_ofs + char_margin, ofs_y + yofs), in_selection && override_selected_font_color ? cache.font_selected_color : color);
}
char_ofs += char_w;
@@ -1604,7 +1635,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
target_v_scroll = 0;
}
scrolling = true;
- set_fixed_process(true);
+ set_physics_process(true);
} else {
v_scroll->set_value(target_v_scroll);
}
@@ -1626,7 +1657,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
target_v_scroll = max_v_scroll;
}
scrolling = true;
- set_fixed_process(true);
+ set_physics_process(true);
} else {
v_scroll->set_value(target_v_scroll);
}
@@ -1766,7 +1797,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (mb->get_button_index() == BUTTON_RIGHT && context_menu_enabled) {
- menu->set_position(get_global_transform().xform(get_local_mouse_pos()));
+ menu->set_position(get_global_transform().xform(get_local_mouse_position()));
menu->set_size(Vector2(1, 1));
menu->popup();
grab_focus();
@@ -1837,7 +1868,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (k->is_pressed()) {
- highlighted_word = get_word_at_pos(get_local_mouse_pos());
+ highlighted_word = get_word_at_pos(get_local_mouse_position());
update();
} else {
@@ -2113,15 +2144,15 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
//keep indentation
int space_count = 0;
- for (int i = 0; i < text[cursor.line].length(); i++) {
- if (text[cursor.line][i] == '\t' && cursor.column > 0) {
+ for (int i = 0; i < cursor.column; i++) {
+ if (text[cursor.line][i] == '\t') {
if (indent_using_spaces) {
ins += space_indent;
} else {
ins += "\t";
}
space_count = 0;
- } else if (text[cursor.line][i] == ' ' && cursor.column > 0) {
+ } else if (text[cursor.line][i] == ' ') {
space_count++;
if (space_count == indent_size) {
@@ -2136,15 +2167,25 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
break;
}
}
- if (auto_indent) {
- // indent once again if previous line will end with ':'
- // (i.e. colon precedes current cursor position)
- if (cursor.column > 0 && text[cursor.line][cursor.column - 1] == ':') {
+
+ bool brace_indent = false;
+
+ // no need to indent if we are going upwards.
+ if (auto_indent && !(k->get_command() && k->get_shift())) {
+ // indent once again if previous line will end with ':' or '{'
+ // (i.e. colon/brace precedes current cursor position)
+ if (cursor.column > 0 && (text[cursor.line][cursor.column - 1] == ':' || text[cursor.line][cursor.column - 1] == '{')) {
if (indent_using_spaces) {
ins += space_indent;
} else {
ins += "\t";
}
+
+ // no need to move the brace below if we are not taking the text with us.
+ if (text[cursor.line][cursor.column] == '}' && !k->get_command()) {
+ brace_indent = true;
+ ins += "\n" + ins.substr(1, ins.length() - 2);
+ }
}
}
@@ -2168,6 +2209,9 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
if (first_line) {
cursor_set_line(0);
+ } else if (brace_indent) {
+ cursor_set_line(cursor.line - 1);
+ cursor_set_column(text[cursor.line].length());
}
} break;
@@ -2780,12 +2824,16 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
int ini = selection.from_line;
int end = selection.to_line;
for (int i = ini; i <= end; i++) {
- if (text[i][0] == '#')
+ if (get_line(i).begins_with("#"))
_remove_text(i, 0, i, 1);
}
} else {
- if (text[cursor.line][0] == '#')
+ if (get_line(cursor.line).begins_with("#")) {
_remove_text(cursor.line, 0, cursor.line, 1);
+ if (cursor.column >= get_line(cursor.line).length()) {
+ cursor.column = MAX(0, get_line(cursor.line).length() - 1);
+ }
+ }
}
update();
}
@@ -3475,7 +3523,7 @@ String TextEdit::get_text() {
String TextEdit::get_text_for_lookup_completion() {
int row, col;
- _get_mouse_pos(get_local_mouse_pos(), row, col);
+ _get_mouse_pos(get_local_mouse_position(), row, col);
String longthing;
int len = text.size();
@@ -4233,6 +4281,13 @@ bool TextEdit::is_drawing_tabs() const {
return draw_tabs;
}
+void TextEdit::set_override_selected_font_color(bool p_override_selected_font_color) {
+ override_selected_font_color = p_override_selected_font_color;
+}
+bool TextEdit::is_overriding_selected_font_color() const {
+ return override_selected_font_color;
+}
+
void TextEdit::set_insert_mode(bool p_enabled) {
insert_mode = p_enabled;
update();
@@ -4242,6 +4297,10 @@ bool TextEdit::is_insert_mode() const {
return insert_mode;
}
+bool TextEdit::is_insert_text_operation() {
+ return (current_op.type == TextOperation::TYPE_INSERT);
+}
+
uint32_t TextEdit::get_version() const {
return current_op.version;
}
@@ -4260,6 +4319,14 @@ int TextEdit::get_v_scroll() const {
}
void TextEdit::set_v_scroll(int p_scroll) {
+ if (p_scroll < 0) {
+ p_scroll = 0;
+ }
+ if (!scroll_past_end_of_file_enabled) {
+ if (p_scroll + get_visible_rows() > get_line_count()) {
+ p_scroll = get_line_count() - get_visible_rows();
+ }
+ }
v_scroll->set_value(p_scroll);
cursor.line_ofs = p_scroll;
}
@@ -4422,7 +4489,13 @@ void TextEdit::_update_completion_candidates() {
completion_index = 0;
completion_base = s;
Vector<float> sim_cache;
+ bool single_quote = s.begins_with("'");
+
for (int i = 0; i < completion_strings.size(); i++) {
+ if (single_quote && completion_strings[i].is_quoted()) {
+ completion_strings[i] = completion_strings[i].unquote().quote("'");
+ }
+
if (s == completion_strings[i]) {
// A perfect match, stop completion
_cancel_completion();
@@ -4531,7 +4604,7 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this
bool inside_quotes = false;
- int qbegin, qend;
+ int qbegin = 0, qend = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] == '"') {
if (inside_quotes) {
@@ -4665,6 +4738,15 @@ int TextEdit::get_breakpoint_gutter_width() const {
return cache.breakpoint_gutter_width;
}
+void TextEdit::set_highlight_current_line(bool p_enabled) {
+ highlight_current_line = p_enabled;
+ update();
+}
+
+bool TextEdit::is_highlight_current_line_enabled() const {
+ return highlight_current_line;
+}
+
bool TextEdit::is_text_field() const {
return true;
@@ -4786,9 +4868,15 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_highlight_all_occurrences", "enable"), &TextEdit::set_highlight_all_occurrences);
ClassDB::bind_method(D_METHOD("is_highlight_all_occurrences_enabled"), &TextEdit::is_highlight_all_occurrences_enabled);
+ ClassDB::bind_method(D_METHOD("set_override_selected_font_color", "override"), &TextEdit::set_override_selected_font_color);
+ ClassDB::bind_method(D_METHOD("is_overriding_selected_font_color"), &TextEdit::is_overriding_selected_font_color);
+
ClassDB::bind_method(D_METHOD("set_syntax_coloring", "enable"), &TextEdit::set_syntax_coloring);
ClassDB::bind_method(D_METHOD("is_syntax_coloring_enabled"), &TextEdit::is_syntax_coloring_enabled);
+ ClassDB::bind_method(D_METHOD("set_highlight_current_line", "enabled"), &TextEdit::set_highlight_current_line);
+ ClassDB::bind_method(D_METHOD("is_highlight_current_line_enabled"), &TextEdit::is_highlight_current_line_enabled);
+
ClassDB::bind_method(D_METHOD("set_smooth_scroll_enable", "enable"), &TextEdit::set_smooth_scroll_enabled);
ClassDB::bind_method(D_METHOD("is_smooth_scroll_enabled"), &TextEdit::is_smooth_scroll_enabled);
ClassDB::bind_method(D_METHOD("set_v_scroll_speed", "speed"), &TextEdit::set_v_scroll_speed);
@@ -4800,9 +4888,11 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("menu_option", "option"), &TextEdit::menu_option);
ClassDB::bind_method(D_METHOD("get_menu"), &TextEdit::get_menu);
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_current_line"), "set_highlight_current_line", "is_highlight_current_line_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "syntax_highlighting"), "set_syntax_coloring", "is_syntax_coloring_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), "set_show_line_numbers", "is_show_line_numbers_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed");
@@ -4833,6 +4923,7 @@ TextEdit::TextEdit() {
readonly = false;
setting_row = false;
draw_tabs = false;
+ override_selected_font_color = false;
draw_caret = true;
max_chars = 0;
clear();
@@ -4919,6 +5010,7 @@ TextEdit::TextEdit() {
auto_brace_completion_enabled = false;
brace_matching_enabled = false;
highlight_all_occurrences = false;
+ highlight_current_line = false;
indent_using_spaces = false;
space_indent = " ";
auto_indent = false;