diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index cb1bfeed6088..f290774e2385 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -6004,7 +6004,7 @@ int TextEdit::get_total_visible_line_count() const { void TextEdit::adjust_viewport_to_caret(int p_caret) { ERR_FAIL_INDEX(p_caret, carets.size()); - // Make sure Caret is visible on the screen. + // Move viewport so the caret is visible on the screen vertically. scrolling = false; minimap_clicked = false; @@ -6024,105 +6024,19 @@ void TextEdit::adjust_viewport_to_caret(int p_caret) { set_line_as_last_visible(cur_line, cur_wrap); } - int visible_width = get_size().width - theme_cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding; - if (draw_minimap) { - visible_width -= minimap_width; - } - if (v_scroll->is_visible_in_tree()) { - visible_width -= v_scroll->get_combined_minimum_size().width; - } - visible_width -= 20; // Give it a little more space. - - if (visible_width <= 0) { - // Not resized yet. - return; - } - - Vector2i caret_pos; - - // Get position of the start of caret. - if (has_ime_text() && ime_selection.x != 0) { - caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x, get_caret_line(p_caret), get_caret_column(p_caret) + ime_selection.x); - } else { - caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret), get_caret_line(p_caret), get_caret_column(p_caret)); - } - - // Get position of the end of caret. - if (has_ime_text()) { - if (ime_selection.y > 0) { - caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret) + ime_selection.x + ime_selection.y); - } else { - caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_text.length(), get_caret_line(p_caret), get_caret_column(p_caret) + ime_text.length()); - } - } else { - caret_pos.y = caret_pos.x; - } - - if (MAX(caret_pos.x, caret_pos.y) > (first_visible_col + visible_width)) { - first_visible_col = MAX(caret_pos.x, caret_pos.y) - visible_width + 1; - } - - if (MIN(caret_pos.x, caret_pos.y) < first_visible_col) { - first_visible_col = MIN(caret_pos.x, caret_pos.y); - } - h_scroll->set_value(first_visible_col); - - queue_redraw(); + _adjust_viewport_to_caret_horizontally(p_caret); } void TextEdit::center_viewport_to_caret(int p_caret) { ERR_FAIL_INDEX(p_caret, carets.size()); - // Move viewport so the caret is in the center of the screen. + // Move viewport so the caret is in the center of the screen vertically. scrolling = false; minimap_clicked = false; set_line_as_center_visible(get_caret_line(p_caret), get_caret_wrap_index(p_caret)); - int visible_width = get_size().width - theme_cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding; - if (draw_minimap) { - visible_width -= minimap_width; - } - if (v_scroll->is_visible_in_tree()) { - visible_width -= v_scroll->get_combined_minimum_size().width; - } - visible_width -= 20; // Give it a little more space. - - if (get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE) { - // Center x offset. - - Vector2i caret_pos; - // Get position of the start of caret. - if (has_ime_text() && ime_selection.x != 0) { - caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x, get_caret_line(p_caret), get_caret_column(p_caret) + ime_selection.x); - } else { - caret_pos.x = _get_column_x_offset_for_line(get_caret_column(p_caret), get_caret_line(p_caret), get_caret_column(p_caret)); - } - - // Get position of the end of caret. - if (has_ime_text()) { - if (ime_selection.y > 0) { - caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_selection.x + ime_selection.y, get_caret_line(p_caret), get_caret_column(p_caret) + ime_selection.x + ime_selection.y); - } else { - caret_pos.y = _get_column_x_offset_for_line(get_caret_column(p_caret) + ime_text.length(), get_caret_line(p_caret), get_caret_column(p_caret) + ime_text.length()); - } - } else { - caret_pos.y = caret_pos.x; - } - - if (MAX(caret_pos.x, caret_pos.y) > (first_visible_col + visible_width)) { - first_visible_col = MAX(caret_pos.x, caret_pos.y) - visible_width + 1; - } - - if (MIN(caret_pos.x, caret_pos.y) < first_visible_col) { - first_visible_col = MIN(caret_pos.x, caret_pos.y); - } - } else { - first_visible_col = 0; - } - h_scroll->set_value(first_visible_col); - - queue_redraw(); + _adjust_viewport_to_caret_horizontally(p_caret); } /* Minimap */ @@ -8212,6 +8126,70 @@ void TextEdit::_scroll_lines_down() { merge_overlapping_carets(); } +void TextEdit::_adjust_viewport_to_caret_horizontally(int p_caret) { + if (get_line_wrapping_mode() != LineWrappingMode::LINE_WRAPPING_NONE) { + first_visible_col = 0; + h_scroll->set_value(first_visible_col); + queue_redraw(); + return; + } + + int visible_width = get_size().width - theme_cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding; + if (draw_minimap) { + visible_width -= minimap_width; + } + if (v_scroll->is_visible_in_tree()) { + visible_width -= v_scroll->get_combined_minimum_size().width; + } + visible_width -= 20; // Give it a little more space. + + if (visible_width <= 0) { + // Not resized yet. + return; + } + + int caret_start_pos; + int caret_end_pos; + bool prioritize_end = true; + + // Get start and end position of the caret. + if (has_ime_text()) { + // Use the size of the IME. + int ime_start_column = get_caret_column(p_caret) + ime_selection.x; + caret_start_pos = _get_column_x_offset_for_line(ime_start_column, get_caret_line(p_caret), ime_start_column); + int ime_end_column = get_caret_column(p_caret) + (ime_selection.y > 0 ? ime_selection.x + ime_selection.y : ime_text.length()); + caret_end_pos = _get_column_x_offset_for_line(ime_end_column, get_caret_line(p_caret), ime_end_column); + prioritize_end = false; + } else if (has_selection(p_caret) && get_selection_from_line(p_caret) == get_selection_to_line(p_caret)) { + // Use selection if it is on one line. + caret_start_pos = _get_column_x_offset_for_line(get_selection_from_column(p_caret), get_caret_line(p_caret), get_selection_from_column(p_caret)); + caret_end_pos = _get_column_x_offset_for_line(get_selection_to_column(p_caret), get_caret_line(p_caret), get_selection_to_column(p_caret)); + prioritize_end = is_caret_after_selection_origin(); + } else { + caret_start_pos = _get_column_x_offset_for_line(get_caret_column(p_caret), get_caret_line(p_caret), get_caret_column(p_caret)); + caret_end_pos = caret_start_pos; + } + + if (caret_start_pos > caret_end_pos) { + // For RTL text. + SWAP(caret_start_pos, caret_end_pos); + prioritize_end = !prioritize_end; + } + + if (!prioritize_end && caret_end_pos > first_visible_col + visible_width) { + first_visible_col = caret_end_pos - visible_width + 1; + } + if (caret_start_pos < first_visible_col) { + first_visible_col = caret_start_pos; + } + if (prioritize_end && caret_end_pos > first_visible_col + visible_width) { + first_visible_col = caret_end_pos - visible_width + 1; + } + + h_scroll->set_value(first_visible_col); + queue_redraw(); +} + // Minimap void TextEdit::_update_minimap_hover() { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 335fe9bf03e6..9109e346c6cf 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -191,9 +191,6 @@ class TextEdit : public Control { int gutter_count = 0; bool indent_wrapped_lines = false; - void _calculate_line_height() const; - void _calculate_max_line_width() const; - public: void set_tab_size(int p_tab_size); int get_tab_size() const; @@ -216,7 +213,6 @@ class TextEdit : public Control { void set_use_custom_word_separators(bool p_enabled); bool is_custom_word_separators_enabled() const; - void set_word_separators(const String &p_separators); void set_custom_word_separators(const String &p_separators); String get_enabled_word_separators() const; String get_custom_word_separators() const; @@ -538,6 +534,8 @@ class TextEdit : public Control { void _scroll_lines_up(); void _scroll_lines_down(); + void _adjust_viewport_to_caret_horizontally(int p_caret = 0); + // Minimap. bool draw_minimap = false;