diff options
Diffstat (limited to 'scene/gui/text_edit.cpp')
-rw-r--r-- | scene/gui/text_edit.cpp | 300 |
1 files changed, 219 insertions, 81 deletions
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 2ca4c81319..7d200a799b 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -376,24 +376,116 @@ void TextEdit::_update_scrollbars() { void TextEdit::_click_selection_held() { if (Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && selection.selecting_mode != Selection::MODE_NONE) { + switch (selection.selecting_mode) { + case Selection::MODE_POINTER: { + _update_selection_mode_pointer(); + } break; + case Selection::MODE_WORD: { + _update_selection_mode_word(); + } break; + case Selection::MODE_LINE: { + _update_selection_mode_line(); + } break; + default: { + break; + } + } + } else { + click_select_held->stop(); + } +} - Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position(); +void TextEdit::_update_selection_mode_pointer() { + Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position(); - int row, col; - _get_mouse_pos(Point2i(mp.x, mp.y), row, col); + int row, col; + _get_mouse_pos(Point2i(mp.x, mp.y), row, col); - select(selection.selecting_line, selection.selecting_column, row, col); + select(selection.selecting_line, selection.selecting_column, row, col); - cursor_set_line(row); - cursor_set_column(col); - update(); + cursor_set_line(row); + cursor_set_column(col); + update(); + + click_select_held->start(); +} - click_select_held->start(); +void TextEdit::_update_selection_mode_word() { + Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position(); + int row, col; + _get_mouse_pos(Point2i(mp.x, mp.y), row, col); + + String line = text[row]; + int beg = CLAMP(col, 0, line.length()); + // if its the first selection and on whitespace make sure we grab the word instead.. + if (!selection.active) { + while (beg > 0 && line[beg] <= 32) { + beg--; + } + } + int end = beg; + bool symbol = beg < line.length() && _is_symbol(line[beg]); + + // get the word end and begin points + while (beg > 0 && line[beg - 1] > 32 && (symbol == _is_symbol(line[beg - 1]))) { + beg--; + } + while (end < line.length() && line[end + 1] > 32 && (symbol == _is_symbol(line[end + 1]))) { + end++; + } + if (end < line.length()) { + end += 1; + } + + // inital selection + if (!selection.active) { + select(row, beg, row, end); + selection.selecting_column = beg; + selection.selected_word_beg = beg; + selection.selected_word_end = end; + selection.selected_word_origin = beg; + cursor_set_column(selection.to_column); } else { + if ((col <= selection.selected_word_origin && row == selection.selecting_line) || row < selection.selecting_line) { + selection.selecting_column = selection.selected_word_end; + select(row, beg, selection.selecting_line, selection.selected_word_end); + cursor_set_column(selection.from_column); + } else { + selection.selecting_column = selection.selected_word_beg; + select(selection.selecting_line, selection.selected_word_beg, row, end); + cursor_set_column(selection.to_column); + } + } + cursor_set_line(row); - click_select_held->stop(); + update(); + click_select_held->start(); +} + +void TextEdit::_update_selection_mode_line() { + Point2 mp = Input::get_singleton()->get_mouse_position() - get_global_position(); + + int row, col; + _get_mouse_pos(Point2i(mp.x, mp.y), row, col); + + col = 0; + if (row < selection.selecting_line) { + // cursor is above us + cursor_set_line(row - 1); + selection.selecting_column = text[selection.selecting_line].length(); + } else { + // cursor is below us + cursor_set_line(row + 1); + selection.selecting_column = 0; + col = text[row].length(); } + cursor_set_column(0); + + select(selection.selecting_line, selection.selecting_column, row, col); + update(); + + click_select_held->start(); } void TextEdit::_notification(int p_what) { @@ -428,22 +520,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 (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: { @@ -501,8 +593,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! @@ -733,8 +824,17 @@ 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 (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 (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); + } + + // 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 (text.is_breakpoint(line) && !draw_breakpoint_gutter) { @@ -765,6 +865,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 @@ -953,10 +1054,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); } @@ -999,7 +1115,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 ( @@ -1008,7 +1124,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); } } @@ -1067,15 +1183,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; @@ -1611,7 +1727,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); } @@ -1633,7 +1749,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); } @@ -1735,36 +1851,15 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (!mb->is_doubleclick() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < 600 && cursor.line == prev_line) { //tripleclick select line - select(cursor.line, 0, cursor.line, text[cursor.line].length()); - selection.selecting_column = 0; + selection.selecting_mode = Selection::MODE_LINE; + _update_selection_mode_line(); last_dblclk = 0; } else if (mb->is_doubleclick() && text[cursor.line].length()) { //doubleclick select world - String s = text[cursor.line]; - int beg = CLAMP(cursor.column, 0, s.length()); - int end = beg; - - if (s[beg] > 32 || beg == s.length()) { - - bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this - - while (beg > 0 && s[beg - 1] > 32 && (symbol == _is_symbol(s[beg - 1]))) { - beg--; - } - while (end < s.length() && s[end + 1] > 32 && (symbol == _is_symbol(s[end + 1]))) { - end++; - } - - if (end < s.length()) - end += 1; - - select(cursor.line, beg, cursor.line, end); - - selection.selecting_column = beg; - } - + selection.selecting_mode = Selection::MODE_WORD; + _update_selection_mode_word(); last_dblclk = OS::get_singleton()->get_ticks_msec(); } @@ -1773,7 +1868,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(); @@ -1809,21 +1904,21 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } if (mm->get_button_mask() & BUTTON_MASK_LEFT && get_viewport()->gui_get_drag_data() == Variant()) { //ignore if dragging + _reset_caret_blink_timer(); - if (selection.selecting_mode != Selection::MODE_NONE) { - - _reset_caret_blink_timer(); - - int row, col; - _get_mouse_pos(mm->get_position(), row, col); - - select(selection.selecting_line, selection.selecting_column, row, col); - - cursor_set_line(row); - cursor_set_column(col); - update(); - - click_select_held->start(); + switch (selection.selecting_mode) { + case Selection::MODE_POINTER: { + _update_selection_mode_pointer(); + } break; + case Selection::MODE_WORD: { + _update_selection_mode_word(); + } break; + case Selection::MODE_LINE: { + _update_selection_mode_line(); + } break; + default: { + break; + } } } } @@ -1844,7 +1939,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 { @@ -2164,7 +2259,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } } - + begin_complex_operation(); bool first_line = false; if (k->get_command()) { if (k->get_shift()) { @@ -2180,8 +2275,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } } - _insert_text_at_cursor(ins); - _push_current_op(); + insert_text_at_cursor(ins); if (first_line) { cursor_set_line(0); @@ -2189,7 +2283,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { cursor_set_line(cursor.line - 1); cursor_set_column(text[cursor.line].length()); } - + end_complex_operation(); } break; case KEY_ESCAPE: { if (completion_hint != "") { @@ -2824,19 +2918,19 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { if (scancode_handled) accept_event(); /* - if (!scancode_handled && !k->get_command() && !k->get_alt()) { + if (!scancode_handled && !k->get_command() && !k->get_alt()) { if (k->get_unicode()>=32) { - if (readonly) + if (readonly) break; - accept_event(); + accept_event(); } else { - break; + break; + } } - } */ if (k->get_scancode() == KEY_INSERT) { set_insert_mode(!insert_mode); @@ -3228,11 +3322,11 @@ void TextEdit::adjust_viewport_to_cursor() { update(); /* - get_range()->set_max(text.size()); + get_range()->set_max(text.size()); - get_range()->set_page(get_visible_rows()); + get_range()->set_page(get_visible_rows()); - get_range()->set((int)cursor.line_ofs); + get_range()->set((int)cursor.line_ofs); */ } @@ -3499,7 +3593,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(); @@ -4257,6 +4351,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(); @@ -4266,6 +4367,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; } @@ -4284,6 +4389,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; } @@ -4446,7 +4559,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(); @@ -4689,6 +4808,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; @@ -4758,8 +4886,8 @@ void TextEdit::_bind_methods() { BIND_ENUM_CONSTANT(SEARCH_BACKWARDS); /* - ClassDB::bind_method(D_METHOD("delete_char"),&TextEdit::delete_char); - ClassDB::bind_method(D_METHOD("delete_line"),&TextEdit::delete_line); + ClassDB::bind_method(D_METHOD("delete_char"),&TextEdit::delete_char); + ClassDB::bind_method(D_METHOD("delete_line"),&TextEdit::delete_line); */ ClassDB::bind_method(D_METHOD("set_text", "text"), &TextEdit::set_text); @@ -4810,9 +4938,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); @@ -4824,9 +4958,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"); @@ -4857,6 +4993,7 @@ TextEdit::TextEdit() { readonly = false; setting_row = false; draw_tabs = false; + override_selected_font_color = false; draw_caret = true; max_chars = 0; clear(); @@ -4943,6 +5080,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; |