diff --git a/doc/classes/TextEdit.xml b/doc/classes/TextEdit.xml
index 00c4c170db8..c89748f3232 100644
--- a/doc/classes/TextEdit.xml
+++ b/doc/classes/TextEdit.xml
@@ -50,6 +50,13 @@
+
+
+
+
+ Adjust the viewport so the caret is visible.
+
+
@@ -135,6 +142,13 @@
+
+
+
+
+ Returns the first visible line.
+
+
@@ -165,6 +179,20 @@
Returns the indent level of a specific line.
+
+
+
+
+ Return the last visible line. Use [method get_last_full_visible_line_wrap_index] for the wrap index.
+
+
+
+
+
+
+ Returns the last visible wrap index of the last visible line.
+
+
@@ -248,6 +276,13 @@
Returns the [PopupMenu] of this [TextEdit]. By default, this menu is displayed when right-clicking on the [TextEdit].
+
+
+
+
+ Gets the total amount of lines that can be draw on the minimap.
+
+
@@ -255,6 +290,24 @@
Returns OpenType feature [code]tag[/code].
+
+
+
+
+
+
+
+
+ Gets the scroll position for [code]wrap_index[/code] of [code]line[/code].
+
+
+
+
+
+
+ Returns the text inside the selection.
+
+
@@ -282,12 +335,6 @@
-
-
-
- Returns the text inside the selection.
-
-
@@ -311,6 +358,13 @@
+
+
+
+
+ Gets the total amount of lines that could be draw.
+
+
@@ -571,6 +625,39 @@
Sets the text for a specific line.
+
+
+
+
+
+
+
+
+ Positions the [code]wrap_index[/code] of [code]line[/code] at the center of the viewport.
+
+
+
+
+
+
+
+
+
+
+ Positions the [code]wrap_index[/code] of [code]line[/code] at the top of the viewport.
+
+
+
+
+
+
+
+
+
+
+ Positions the [code]wrap_index[/code] of [code]line[/code] at the bottom of the viewport.
+
+
@@ -714,6 +801,9 @@
If there is a horizontal scrollbar, this determines the current horizontal scroll value in pixels.
+
+ Allow scrolling past the last line into "virtual" space.
+
If there is a vertical scrollbar, this determines the current vertical scroll value in line numbers, starting at 0 for the top line.
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 5f6b7e17885..540ba8c19d0 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -951,7 +951,7 @@ void CodeTextEditor::update_editor_settings() {
text_editor->set_line_folding_enabled(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding"));
text_editor->set_draw_fold_gutter(EditorSettings::get_singleton()->get("text_editor/appearance/code_folding"));
text_editor->set_line_wrapping_mode((TextEdit::LineWrappingMode)EditorSettings::get_singleton()->get("text_editor/appearance/word_wrap").operator int());
- text_editor->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/cursor/scroll_past_end_of_file"));
+ text_editor->set_scroll_past_end_of_file_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/scroll_past_end_of_file"));
text_editor->set_caret_type((TextEdit::CaretType)EditorSettings::get_singleton()->get("text_editor/cursor/type").operator int());
text_editor->set_caret_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink"));
text_editor->set_caret_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed"));
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index e3090a56c58..5d832a64a15 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -251,70 +251,6 @@ void TextEdit::Text::move_gutters(int p_from_line, int p_to_line) {
////////////////////////////////////////////////////////////////////////////////
-void TextEdit::_update_scrollbars() {
- Size2 size = get_size();
- Size2 hmin = h_scroll->get_combined_minimum_size();
- Size2 vmin = v_scroll->get_combined_minimum_size();
-
- v_scroll->set_begin(Point2(size.width - vmin.width, cache.style_normal->get_margin(SIDE_TOP)));
- v_scroll->set_end(Point2(size.width, size.height - cache.style_normal->get_margin(SIDE_TOP) - cache.style_normal->get_margin(SIDE_BOTTOM)));
-
- h_scroll->set_begin(Point2(0, size.height - hmin.height));
- h_scroll->set_end(Point2(size.width - vmin.width, size.height));
-
- int visible_rows = get_visible_rows();
- int total_rows = get_total_visible_rows();
- if (scroll_past_end_of_file_enabled) {
- total_rows += visible_rows - 1;
- }
-
- int visible_width = size.width - cache.style_normal->get_minimum_size().width;
- int total_width = text.get_max_width(true) + vmin.x + gutters_width + gutter_padding;
-
- if (draw_minimap) {
- total_width += cache.minimap_width;
- }
-
- updating_scrolls = true;
-
- if (total_rows > visible_rows) {
- v_scroll->show();
- v_scroll->set_max(total_rows + get_visible_rows_offset());
- v_scroll->set_page(visible_rows + get_visible_rows_offset());
- if (smooth_scroll_enabled) {
- v_scroll->set_step(0.25);
- } else {
- v_scroll->set_step(1);
- }
- set_v_scroll(get_v_scroll());
-
- } else {
- caret.line_ofs = 0;
- caret.wrap_ofs = 0;
- v_scroll->set_value(0);
- v_scroll->hide();
- }
-
- if (total_width > visible_width && get_line_wrapping_mode() == LineWrappingMode::LINE_WRAPPING_NONE) {
- h_scroll->show();
- h_scroll->set_max(total_width);
- h_scroll->set_page(visible_width);
- if (caret.x_ofs > (total_width - visible_width)) {
- caret.x_ofs = (total_width - visible_width);
- }
- if (fabs(h_scroll->get_value() - (double)caret.x_ofs) >= 1) {
- h_scroll->set_value(caret.x_ofs);
- }
-
- } else {
- caret.x_ofs = 0;
- h_scroll->set_value(0);
- h_scroll->hide();
- }
-
- updating_scrolls = false;
-}
-
Point2 TextEdit::_get_local_mouse_pos() const {
Point2 mp = get_local_mouse_position();
if (is_layout_rtl()) {
@@ -323,54 +259,6 @@ Point2 TextEdit::_get_local_mouse_pos() const {
return mp;
}
-void TextEdit::_update_minimap_click() {
- Point2 mp = _get_local_mouse_pos();
-
- int xmargin_end = get_size().width - cache.style_normal->get_margin(SIDE_RIGHT);
- if (!dragging_minimap && (mp.x < xmargin_end - minimap_width || mp.y > xmargin_end)) {
- minimap_clicked = false;
- return;
- }
- minimap_clicked = true;
- dragging_minimap = true;
-
- int row;
- _get_minimap_mouse_row(Point2i(mp.x, mp.y), row);
-
- if (row >= get_first_visible_line() && (row < get_last_full_visible_line() || row >= (text.size() - 1))) {
- minimap_scroll_ratio = v_scroll->get_as_ratio();
- minimap_scroll_click_pos = mp.y;
- can_drag_minimap = true;
- return;
- }
-
- int wi;
- int first_line = row - num_lines_from_rows(row, 0, -get_visible_rows() / 2, wi) + 1;
- double delta = get_scroll_pos_for_line(first_line, wi) - get_v_scroll();
- if (delta < 0) {
- _scroll_up(-delta);
- } else {
- _scroll_down(delta);
- }
-}
-
-void TextEdit::_update_minimap_drag() {
- if (!can_drag_minimap) {
- return;
- }
-
- int control_height = _get_control_height();
- int scroll_height = v_scroll->get_max() * (minimap_char_size.y + minimap_line_spacing);
- if (control_height > scroll_height) {
- control_height = scroll_height;
- }
-
- Point2 mp = _get_local_mouse_pos();
-
- double diff = (mp.y - minimap_scroll_click_pos) / control_height;
- v_scroll->set_as_ratio(minimap_scroll_ratio + diff);
-}
-
void TextEdit::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -450,18 +338,16 @@ void TextEdit::_notification(int p_what) {
draw_caret = false;
}
- cache.minimap_width = 0;
- if (draw_minimap) {
- cache.minimap_width = minimap_width;
- }
-
_update_scrollbars();
RID ci = get_canvas_item();
RenderingServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true);
int xmargin_beg = cache.style_normal->get_margin(SIDE_LEFT) + gutters_width + gutter_padding;
- int xmargin_end = size.width - cache.style_normal->get_margin(SIDE_RIGHT) - cache.minimap_width;
+ int xmargin_end = size.width - cache.style_normal->get_margin(SIDE_RIGHT);
+ if (draw_minimap) {
+ xmargin_end -= minimap_width;
+ }
// Let's do it easy for now.
cache.style_normal->draw(ci, Rect2(Point2(), size));
if (!editable) {
@@ -472,7 +358,7 @@ void TextEdit::_notification(int p_what) {
cache.style_focus->draw(ci, Rect2(Point2(), size));
}
- int visible_rows = get_visible_rows() + 1;
+ int visible_rows = get_visible_line_count() + 1;
Color color = !editable ? cache.font_readonly_color : cache.font_color;
@@ -638,7 +524,7 @@ void TextEdit::_notification(int p_what) {
// minimap
if (draw_minimap) {
- int minimap_visible_lines = _get_minimap_visible_rows();
+ int minimap_visible_lines = get_minimap_visible_lines();
int minimap_line_height = (minimap_char_size.y + minimap_line_spacing);
int minimap_tab_size = minimap_char_size.x * text.get_tab_size();
@@ -660,9 +546,9 @@ void TextEdit::_notification(int p_what) {
// draw the minimap
Color viewport_color = (cache.background_color.get_v() < 0.5) ? Color(1, 1, 1, 0.1) : Color(0, 0, 0, 0.1);
if (rtl) {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - cache.minimap_width, viewport_offset_y, cache.minimap_width, viewport_height), viewport_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - minimap_width, viewport_offset_y, minimap_width, viewport_height), viewport_color);
} else {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), viewport_offset_y, cache.minimap_width, viewport_height), viewport_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), viewport_offset_y, minimap_width, viewport_height), viewport_color);
}
for (int i = 0; i < minimap_draw_amount; i++) {
minimap_line++;
@@ -716,15 +602,15 @@ void TextEdit::_notification(int p_what) {
if (minimap_line == caret.line && caret_wrap_index == line_wrap_index && highlight_current_line) {
if (rtl) {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - cache.minimap_width, i * 3, cache.minimap_width, 2), cache.current_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - minimap_width, i * 3, minimap_width, 2), cache.current_line_color);
} else {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), i * 3, cache.minimap_width, 2), cache.current_line_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), i * 3, minimap_width, 2), cache.current_line_color);
}
} else if (line_background_color != Color(0, 0, 0, 0)) {
if (rtl) {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - cache.minimap_width, i * 3, cache.minimap_width, 2), line_background_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(size.width - (xmargin_end + 2) - minimap_width, i * 3, minimap_width, 2), line_background_color);
} else {
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), i * 3, cache.minimap_width, 2), line_background_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2((xmargin_end + 2), i * 3, minimap_width, 2), line_background_color);
}
}
@@ -745,7 +631,7 @@ void TextEdit::_notification(int p_what) {
}
int xpos = indent_px + ((xmargin_end + minimap_char_size.x) + (minimap_char_size.x * j)) + tabs;
- bool out_of_bounds = (xpos >= xmargin_end + cache.minimap_width);
+ bool out_of_bounds = (xpos >= xmargin_end + minimap_width);
bool is_whitespace = _is_whitespace(str[j]);
if (!is_whitespace) {
@@ -859,7 +745,7 @@ void TextEdit::_notification(int p_what) {
ofs_y += i * row_height + cache.line_spacing / 2;
ofs_y -= caret.wrap_ofs * row_height;
- ofs_y -= get_v_scroll_offset() * row_height;
+ ofs_y -= _get_v_scroll_offset() * row_height;
bool clipped = false;
if (ofs_y + row_height < top_limit_y) {
@@ -1651,7 +1537,7 @@ void TextEdit::_move_caret_page_up(bool p_select) {
}
int wi;
- int n_line = caret.line - num_lines_from_rows(caret.line, get_caret_wrap_index(), -get_visible_rows(), wi) + 1;
+ int n_line = caret.line - num_lines_from_rows(caret.line, get_caret_wrap_index(), -get_visible_line_count(), wi) + 1;
set_caret_line(n_line, true, false, wi);
if (p_select) {
@@ -1667,7 +1553,7 @@ void TextEdit::_move_caret_page_down(bool p_select) {
}
int wi;
- int n_line = caret.line + num_lines_from_rows(caret.line, get_caret_wrap_index(), get_visible_rows(), wi) - 1;
+ int n_line = caret.line + num_lines_from_rows(caret.line, get_caret_wrap_index(), get_visible_line_count(), wi) - 1;
set_caret_line(n_line, true, false, wi);
if (p_select) {
@@ -1797,7 +1683,7 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
float rows = p_mouse.y;
rows -= cache.style_normal->get_margin(SIDE_TOP);
rows /= get_row_height();
- rows += get_v_scroll_offset();
+ rows += _get_v_scroll_offset();
int first_vis_line = get_first_visible_line();
int row = first_vis_line + Math::floor(rows);
int wrap_index = 0;
@@ -1851,11 +1737,11 @@ void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const
float rows = p_mouse.y;
rows -= cache.style_normal->get_margin(SIDE_TOP);
rows /= (minimap_char_size.y + minimap_line_spacing);
- rows += get_v_scroll_offset();
+ rows += _get_v_scroll_offset();
// calculate visible lines
- int minimap_visible_lines = _get_minimap_visible_rows();
- int visible_rows = get_visible_rows() + 1;
+ int minimap_visible_lines = get_minimap_visible_lines();
+ int visible_rows = get_visible_line_count() + 1;
int first_visible_line = get_first_visible_line() - 1;
int draw_amount = visible_rows + (smooth_scroll_enabled ? 1 : 0);
draw_amount += get_line_wrap_count(first_visible_line + 1);
@@ -1864,7 +1750,7 @@ void TextEdit::_get_minimap_mouse_row(const Point2i &p_mouse, int &r_row) const
// calculate viewport size and y offset
int viewport_height = (draw_amount - 1) * minimap_line_height;
int control_height = _get_control_height() - viewport_height;
- int viewport_offset_y = round(get_scroll_pos_for_line(first_visible_line) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount));
+ int viewport_offset_y = round(get_scroll_pos_for_line(first_visible_line + 1) * control_height) / ((v_scroll->get_max() <= minimap_visible_lines) ? (minimap_visible_lines - draw_amount) : (v_scroll->get_max() - draw_amount));
// calculate the first line.
int num_lines_before = round((viewport_offset_y) / minimap_line_height);
@@ -2383,101 +2269,6 @@ void TextEdit::_gui_input(const Ref &p_gui_input) {
}
}
-void TextEdit::_scroll_up(real_t p_delta) {
- if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(-p_delta)) {
- scrolling = false;
- minimap_clicked = false;
- }
-
- if (scrolling) {
- target_v_scroll = (target_v_scroll - p_delta);
- } else {
- target_v_scroll = (get_v_scroll() - p_delta);
- }
-
- if (smooth_scroll_enabled) {
- if (target_v_scroll <= 0) {
- target_v_scroll = 0;
- }
- if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) {
- v_scroll->set_value(target_v_scroll);
- } else {
- scrolling = true;
- set_physics_process_internal(true);
- }
- } else {
- set_v_scroll(target_v_scroll);
- }
-}
-
-void TextEdit::_scroll_down(real_t p_delta) {
- if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(p_delta)) {
- scrolling = false;
- minimap_clicked = false;
- }
-
- if (scrolling) {
- target_v_scroll = (target_v_scroll + p_delta);
- } else {
- target_v_scroll = (get_v_scroll() + p_delta);
- }
-
- if (smooth_scroll_enabled) {
- int max_v_scroll = round(v_scroll->get_max() - v_scroll->get_page());
- if (target_v_scroll > max_v_scroll) {
- target_v_scroll = max_v_scroll;
- }
- if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) {
- v_scroll->set_value(target_v_scroll);
- } else {
- scrolling = true;
- set_physics_process_internal(true);
- }
- } else {
- set_v_scroll(target_v_scroll);
- }
-}
-
-void TextEdit::_scroll_lines_up() {
- scrolling = false;
- minimap_clicked = false;
-
- // Adjust the vertical scroll.
- set_v_scroll(get_v_scroll() - 1);
-
- // Adjust the caret to viewport.
- if (!selection.active) {
- int cur_line = caret.line;
- int cur_wrap = get_caret_wrap_index();
- int last_vis_line = get_last_full_visible_line();
- int last_vis_wrap = get_last_full_visible_line_wrap_index();
-
- if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) {
- set_caret_line(last_vis_line, false, false, last_vis_wrap);
- }
- }
-}
-
-void TextEdit::_scroll_lines_down() {
- scrolling = false;
- minimap_clicked = false;
-
- // Adjust the vertical scroll.
- set_v_scroll(get_v_scroll() + 1);
-
- // Adjust the caret to viewport.
- if (!selection.active) {
- int cur_line = caret.line;
- int cur_wrap = get_caret_wrap_index();
- int first_vis_line = get_first_visible_line();
- int first_vis_wrap = caret.wrap_ofs;
-
- if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
- set_caret_line(first_vis_line, false, false, first_vis_wrap);
- }
- }
-}
-
/**** TEXT EDIT CORE API ****/
void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, int &r_end_line, int &r_end_column) {
@@ -2737,183 +2528,6 @@ int TextEdit::_get_menu_action_accelerator(const String &p_action) {
}
}
-int TextEdit::get_visible_rows() const {
- return _get_control_height() / get_row_height();
-}
-
-int TextEdit::_get_minimap_visible_rows() const {
- return _get_control_height() / (minimap_char_size.y + minimap_line_spacing);
-}
-
-int TextEdit::get_total_visible_rows() const {
- // Returns the total amount of rows we need in the editor.
- // This skips hidden lines and counts each wrapping of a line.
- if (!_is_hiding_enabled() && get_line_wrapping_mode() == LineWrappingMode::LINE_WRAPPING_NONE) {
- return text.size();
- }
-
- int total_rows = 0;
- for (int i = 0; i < text.size(); i++) {
- if (!text.is_hidden(i)) {
- total_rows++;
- total_rows += get_line_wrap_count(i);
- }
- }
- return total_rows;
-}
-
-void TextEdit::adjust_viewport_to_caret() {
- // Make sure Caret is visible on the screen.
- scrolling = false;
- minimap_clicked = false;
-
- int cur_line = caret.line;
- int cur_wrap = get_caret_wrap_index();
-
- int first_vis_line = get_first_visible_line();
- int first_vis_wrap = caret.wrap_ofs;
- int last_vis_line = get_last_full_visible_line();
- int last_vis_wrap = get_last_full_visible_line_wrap_index();
-
- if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
- // Caret is above screen.
- set_line_as_first_visible(cur_line, cur_wrap);
- } else if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) {
- // Caret is below screen.
- set_line_as_last_visible(cur_line, cur_wrap);
- }
-
- int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding - cache.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) {
- // Adjust x offset.
- Vector2i caret_pos;
-
- // Get position of the start of caret.
- if (ime_text.length() != 0 && ime_selection.x != 0) {
- caret_pos.x = get_column_x_offset_for_line(caret.column + ime_selection.x, caret.line);
- } else {
- caret_pos.x = get_column_x_offset_for_line(caret.column, caret.line);
- }
-
- // Get position of the end of caret.
- if (ime_text.length() != 0) {
- if (ime_selection.y != 0) {
- caret_pos.y = get_column_x_offset_for_line(caret.column + ime_selection.x + ime_selection.y, caret.line);
- } else {
- caret_pos.y = get_column_x_offset_for_line(caret.column + ime_text.size(), caret.line);
- }
- } else {
- caret_pos.y = caret_pos.x;
- }
-
- if (MAX(caret_pos.x, caret_pos.y) > (caret.x_ofs + visible_width)) {
- caret.x_ofs = MAX(caret_pos.x, caret_pos.y) - visible_width + 1;
- }
-
- if (MIN(caret_pos.x, caret_pos.y) < caret.x_ofs) {
- caret.x_ofs = MIN(caret_pos.x, caret_pos.y);
- }
- } else {
- caret.x_ofs = 0;
- }
- h_scroll->set_value(caret.x_ofs);
-
- update();
-}
-
-void TextEdit::center_viewport_to_caret() {
- // Move viewport so the caret is in the center of the screen.
- scrolling = false;
- minimap_clicked = false;
-
- set_line_as_center_visible(caret.line, get_caret_wrap_index());
- int visible_width = get_size().width - cache.style_normal->get_minimum_size().width - gutters_width - gutter_padding - cache.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 (ime_text.length() != 0 && ime_selection.x != 0) {
- caret_pos.x = get_column_x_offset_for_line(caret.column + ime_selection.x, caret.line);
- } else {
- caret_pos.x = get_column_x_offset_for_line(caret.column, caret.line);
- }
-
- // Get position of the end of caret.
- if (ime_text.length() != 0) {
- if (ime_selection.y != 0) {
- caret_pos.y = get_column_x_offset_for_line(caret.column + ime_selection.x + ime_selection.y, caret.line);
- } else {
- caret_pos.y = get_column_x_offset_for_line(caret.column + ime_text.size(), caret.line);
- }
- } else {
- caret_pos.y = caret_pos.x;
- }
-
- if (MAX(caret_pos.x, caret_pos.y) > (caret.x_ofs + visible_width)) {
- caret.x_ofs = MAX(caret_pos.x, caret_pos.y) - visible_width + 1;
- }
-
- if (MIN(caret_pos.x, caret_pos.y) < caret.x_ofs) {
- caret.x_ofs = MIN(caret_pos.x, caret_pos.y);
- }
- } else {
- caret.x_ofs = 0;
- }
- h_scroll->set_value(caret.x_ofs);
-
- update();
-}
-
-void TextEdit::_v_scroll_input() {
- scrolling = false;
- minimap_clicked = false;
-}
-
-void TextEdit::_scroll_moved(double p_to_val) {
- if (updating_scrolls) {
- return;
- }
-
- if (h_scroll->is_visible_in_tree()) {
- caret.x_ofs = h_scroll->get_value();
- }
- if (v_scroll->is_visible_in_tree()) {
- // Set line ofs and wrap ofs.
- int v_scroll_i = floor(get_v_scroll());
- int sc = 0;
- int n_line;
- for (n_line = 0; n_line < text.size(); n_line++) {
- if (!_is_line_hidden(n_line)) {
- sc++;
- sc += get_line_wrap_count(n_line);
- if (sc > v_scroll_i) {
- break;
- }
- }
- }
- n_line = MIN(n_line, text.size() - 1);
- int line_wrap_amount = get_line_wrap_count(n_line);
- int wi = line_wrap_amount - (sc - v_scroll_i - 1);
- wi = CLAMP(wi, 0, line_wrap_amount);
-
- caret.line_ofs = n_line;
- caret.wrap_ofs = wi;
- }
- update();
-}
-
int TextEdit::get_row_height() const {
int height = cache.font->get_height(cache.font_size);
for (int i = 0; i < text.size(); i++) {
@@ -3705,6 +3319,8 @@ int TextEdit::get_line_wrap_count(int p_line) const {
int TextEdit::get_line_wrap_index_at_column(int p_line, int p_column) const {
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
+ ERR_FAIL_COND_V(p_column < 0, 0);
+ ERR_FAIL_COND_V(p_column > text[p_line].length(), 0);
if (!is_line_wrapped(p_line)) {
return 0;
@@ -3743,6 +3359,300 @@ Vector TextEdit::get_line_wrapped_text(int p_line) const {
return lines;
}
+/* Viewport */
+// Scrolling.
+void TextEdit::set_smooth_scroll_enabled(const bool p_enable) {
+ v_scroll->set_smooth_scroll_enabled(p_enable);
+ smooth_scroll_enabled = p_enable;
+}
+
+bool TextEdit::is_smooth_scroll_enabled() const {
+ return smooth_scroll_enabled;
+}
+
+void TextEdit::set_scroll_past_end_of_file_enabled(const bool p_enabled) {
+ scroll_past_end_of_file_enabled = p_enabled;
+ update();
+}
+
+bool TextEdit::is_scroll_past_end_of_file_enabled() const {
+ return scroll_past_end_of_file_enabled;
+}
+
+void TextEdit::set_v_scroll(double p_scroll) {
+ v_scroll->set_value(p_scroll);
+ int max_v_scroll = v_scroll->get_max() - v_scroll->get_page();
+ if (p_scroll >= max_v_scroll - 1.0) {
+ _scroll_moved(v_scroll->get_value());
+ }
+}
+
+double TextEdit::get_v_scroll() const {
+ return v_scroll->get_value();
+}
+
+void TextEdit::set_h_scroll(int p_scroll) {
+ if (p_scroll < 0) {
+ p_scroll = 0;
+ }
+ h_scroll->set_value(p_scroll);
+}
+
+int TextEdit::get_h_scroll() const {
+ return h_scroll->get_value();
+}
+
+void TextEdit::set_v_scroll_speed(float p_speed) {
+ v_scroll_speed = p_speed;
+}
+
+float TextEdit::get_v_scroll_speed() const {
+ return v_scroll_speed;
+}
+
+double TextEdit::get_scroll_pos_for_line(int p_line, int p_wrap_index) const {
+ ERR_FAIL_INDEX_V(p_line, text.size(), 0);
+ ERR_FAIL_COND_V(p_wrap_index < 0, 0);
+ ERR_FAIL_COND_V(p_wrap_index > get_line_wrap_count(p_line), 0);
+
+ if (get_line_wrapping_mode() == LineWrappingMode::LINE_WRAPPING_NONE && !_is_hiding_enabled()) {
+ return p_line;
+ }
+
+ // Count the number of visible lines up to this line.
+ double new_line_scroll_pos = 0.0;
+ int to = CLAMP(p_line, 0, text.size() - 1);
+ for (int i = 0; i < to; i++) {
+ if (!text.is_hidden(i)) {
+ new_line_scroll_pos++;
+ new_line_scroll_pos += get_line_wrap_count(i);
+ }
+ }
+ new_line_scroll_pos += p_wrap_index;
+ return new_line_scroll_pos;
+}
+
+// Visible lines.
+void TextEdit::set_line_as_first_visible(int p_line, int p_wrap_index) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ ERR_FAIL_COND(p_wrap_index < 0);
+ ERR_FAIL_COND(p_wrap_index > get_line_wrap_count(p_line));
+ set_v_scroll(get_scroll_pos_for_line(p_line, p_wrap_index));
+}
+
+int TextEdit::get_first_visible_line() const {
+ return CLAMP(caret.line_ofs, 0, text.size() - 1);
+}
+
+void TextEdit::set_line_as_center_visible(int p_line, int p_wrap_index) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ ERR_FAIL_COND(p_wrap_index < 0);
+ ERR_FAIL_COND(p_wrap_index > get_line_wrap_count(p_line));
+
+ int visible_rows = get_visible_line_count();
+ int wi;
+ int first_line = p_line - num_lines_from_rows(p_line, p_wrap_index, -visible_rows / 2, wi) + 1;
+
+ set_v_scroll(get_scroll_pos_for_line(first_line, wi));
+}
+
+void TextEdit::set_line_as_last_visible(int p_line, int p_wrap_index) {
+ ERR_FAIL_INDEX(p_line, text.size());
+ ERR_FAIL_COND(p_wrap_index < 0);
+ ERR_FAIL_COND(p_wrap_index > get_line_wrap_count(p_line));
+
+ int wi;
+ int first_line = p_line - num_lines_from_rows(p_line, p_wrap_index, -get_visible_line_count() - 1, wi) + 1;
+
+ set_v_scroll(get_scroll_pos_for_line(first_line, wi) + _get_visible_lines_offset());
+}
+
+int TextEdit::get_last_full_visible_line() const {
+ int first_vis_line = get_first_visible_line();
+ int last_vis_line = 0;
+ int wi;
+ last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, caret.wrap_ofs, get_visible_line_count(), wi) - 1;
+ last_vis_line = CLAMP(last_vis_line, 0, text.size() - 1);
+ return last_vis_line;
+}
+
+int TextEdit::get_last_full_visible_line_wrap_index() const {
+ int first_vis_line = get_first_visible_line();
+ int wi;
+ num_lines_from_rows(first_vis_line, caret.wrap_ofs, get_visible_line_count(), wi);
+ return wi;
+}
+
+int TextEdit::get_visible_line_count() const {
+ return _get_control_height() / get_row_height();
+}
+
+int TextEdit::get_total_visible_line_count() const {
+ /* Returns the total number of (lines + wraped - hidden). */
+ if (!_is_hiding_enabled() && get_line_wrapping_mode() == LineWrappingMode::LINE_WRAPPING_NONE) {
+ return text.size();
+ }
+
+ int total_rows = 0;
+ for (int i = 0; i < text.size(); i++) {
+ if (!text.is_hidden(i)) {
+ total_rows++;
+ total_rows += get_line_wrap_count(i);
+ }
+ }
+ return total_rows;
+}
+
+// Auto adjust
+void TextEdit::adjust_viewport_to_caret() {
+ // Make sure Caret is visible on the screen.
+ scrolling = false;
+ minimap_clicked = false;
+
+ int cur_line = caret.line;
+ int cur_wrap = get_caret_wrap_index();
+
+ int first_vis_line = get_first_visible_line();
+ int first_vis_wrap = caret.wrap_ofs;
+ int last_vis_line = get_last_full_visible_line();
+ int last_vis_wrap = get_last_full_visible_line_wrap_index();
+
+ if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
+ // Caret is above screen.
+ set_line_as_first_visible(cur_line, cur_wrap);
+ } else if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) {
+ // Caret is below screen.
+ set_line_as_last_visible(cur_line, cur_wrap);
+ }
+
+ int visible_width = get_size().width - 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) {
+ // Adjust x offset.
+ Vector2i caret_pos;
+
+ // Get position of the start of caret.
+ if (ime_text.length() != 0 && ime_selection.x != 0) {
+ caret_pos.x = get_column_x_offset_for_line(caret.column + ime_selection.x, caret.line);
+ } else {
+ caret_pos.x = get_column_x_offset_for_line(caret.column, caret.line);
+ }
+
+ // Get position of the end of caret.
+ if (ime_text.length() != 0) {
+ if (ime_selection.y != 0) {
+ caret_pos.y = get_column_x_offset_for_line(caret.column + ime_selection.x + ime_selection.y, caret.line);
+ } else {
+ caret_pos.y = get_column_x_offset_for_line(caret.column + ime_text.size(), caret.line);
+ }
+ } else {
+ caret_pos.y = caret_pos.x;
+ }
+
+ if (MAX(caret_pos.x, caret_pos.y) > (caret.x_ofs + visible_width)) {
+ caret.x_ofs = MAX(caret_pos.x, caret_pos.y) - visible_width + 1;
+ }
+
+ if (MIN(caret_pos.x, caret_pos.y) < caret.x_ofs) {
+ caret.x_ofs = MIN(caret_pos.x, caret_pos.y);
+ }
+ } else {
+ caret.x_ofs = 0;
+ }
+ h_scroll->set_value(caret.x_ofs);
+
+ update();
+}
+
+void TextEdit::center_viewport_to_caret() {
+ // Move viewport so the caret is in the center of the screen.
+ scrolling = false;
+ minimap_clicked = false;
+
+ set_line_as_center_visible(caret.line, get_caret_wrap_index());
+ int visible_width = get_size().width - 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 (ime_text.length() != 0 && ime_selection.x != 0) {
+ caret_pos.x = get_column_x_offset_for_line(caret.column + ime_selection.x, caret.line);
+ } else {
+ caret_pos.x = get_column_x_offset_for_line(caret.column, caret.line);
+ }
+
+ // Get position of the end of caret.
+ if (ime_text.length() != 0) {
+ if (ime_selection.y != 0) {
+ caret_pos.y = get_column_x_offset_for_line(caret.column + ime_selection.x + ime_selection.y, caret.line);
+ } else {
+ caret_pos.y = get_column_x_offset_for_line(caret.column + ime_text.size(), caret.line);
+ }
+ } else {
+ caret_pos.y = caret_pos.x;
+ }
+
+ if (MAX(caret_pos.x, caret_pos.y) > (caret.x_ofs + visible_width)) {
+ caret.x_ofs = MAX(caret_pos.x, caret_pos.y) - visible_width + 1;
+ }
+
+ if (MIN(caret_pos.x, caret_pos.y) < caret.x_ofs) {
+ caret.x_ofs = MIN(caret_pos.x, caret_pos.y);
+ }
+ } else {
+ caret.x_ofs = 0;
+ }
+ h_scroll->set_value(caret.x_ofs);
+
+ update();
+}
+
+/* Minimap */
+void TextEdit::set_draw_minimap(bool p_draw) {
+ if (draw_minimap != p_draw) {
+ draw_minimap = p_draw;
+ _update_wrap_at_column();
+ }
+ update();
+}
+
+bool TextEdit::is_drawing_minimap() const {
+ return draw_minimap;
+}
+
+void TextEdit::set_minimap_width(int p_minimap_width) {
+ if (minimap_width != p_minimap_width) {
+ minimap_width = p_minimap_width;
+ _update_wrap_at_column();
+ }
+ update();
+}
+
+int TextEdit::get_minimap_width() const {
+ return minimap_width;
+}
+
+int TextEdit::get_minimap_visible_lines() const {
+ return _get_control_height() / (minimap_char_size.y + minimap_line_spacing);
+}
+
/* Syntax Highlighting. */
Ref TextEdit::get_syntax_highlighter() {
return syntax_highlighter;
@@ -3780,7 +3690,7 @@ void TextEdit::add_gutter(int p_at) {
for (int i = 0; i < text.size() + 1; i++) {
text.add_gutter(p_at);
}
- emit_signal(SNAME("gutter_added"));
+ emit_signal("gutter_added");
update();
}
@@ -3792,7 +3702,7 @@ void TextEdit::remove_gutter(int p_gutter) {
for (int i = 0; i < text.size() + 1; i++) {
text.remove_gutter(p_gutter);
}
- emit_signal(SNAME("gutter_removed"));
+ emit_signal("gutter_removed");
update();
}
@@ -4541,116 +4451,6 @@ void TextEdit::tag_saved_version() {
saved_version = get_version();
}
-double TextEdit::get_scroll_pos_for_line(int p_line, int p_wrap_index) const {
- if (get_line_wrapping_mode() == LineWrappingMode::LINE_WRAPPING_NONE && !_is_hiding_enabled()) {
- return p_line;
- }
-
- // Count the number of visible lines up to this line.
- double new_line_scroll_pos = 0.0;
- int to = CLAMP(p_line, 0, text.size() - 1);
- for (int i = 0; i < to; i++) {
- if (!text.is_hidden(i)) {
- new_line_scroll_pos++;
- new_line_scroll_pos += get_line_wrap_count(i);
- }
- }
- new_line_scroll_pos += p_wrap_index;
- return new_line_scroll_pos;
-}
-
-void TextEdit::set_line_as_first_visible(int p_line, int p_wrap_index) {
- set_v_scroll(get_scroll_pos_for_line(p_line, p_wrap_index));
-}
-
-void TextEdit::set_line_as_center_visible(int p_line, int p_wrap_index) {
- int visible_rows = get_visible_rows();
- int wi;
- int first_line = p_line - num_lines_from_rows(p_line, p_wrap_index, -visible_rows / 2, wi) + 1;
-
- set_v_scroll(get_scroll_pos_for_line(first_line, wi));
-}
-
-void TextEdit::set_line_as_last_visible(int p_line, int p_wrap_index) {
- int wi;
- int first_line = p_line - num_lines_from_rows(p_line, p_wrap_index, -get_visible_rows() - 1, wi) + 1;
-
- set_v_scroll(get_scroll_pos_for_line(first_line, wi) + get_visible_rows_offset());
-}
-
-int TextEdit::get_first_visible_line() const {
- return CLAMP(caret.line_ofs, 0, text.size() - 1);
-}
-
-int TextEdit::get_last_full_visible_line() const {
- int first_vis_line = get_first_visible_line();
- int last_vis_line = 0;
- int wi;
- last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, caret.wrap_ofs, get_visible_rows(), wi) - 1;
- last_vis_line = CLAMP(last_vis_line, 0, text.size() - 1);
- return last_vis_line;
-}
-
-int TextEdit::get_last_full_visible_line_wrap_index() const {
- int first_vis_line = get_first_visible_line();
- int wi;
- num_lines_from_rows(first_vis_line, caret.wrap_ofs, get_visible_rows(), wi);
- return wi;
-}
-
-double TextEdit::get_visible_rows_offset() const {
- double total = _get_control_height();
- total /= (double)get_row_height();
- total = total - floor(total);
- total = -CLAMP(total, 0.001, 1) + 1;
- return total;
-}
-
-double TextEdit::get_v_scroll_offset() const {
- double val = get_v_scroll() - floor(get_v_scroll());
- return CLAMP(val, 0, 1);
-}
-
-double TextEdit::get_v_scroll() const {
- return v_scroll->get_value();
-}
-
-void TextEdit::set_v_scroll(double p_scroll) {
- v_scroll->set_value(p_scroll);
- int max_v_scroll = v_scroll->get_max() - v_scroll->get_page();
- if (p_scroll >= max_v_scroll - 1.0) {
- _scroll_moved(v_scroll->get_value());
- }
-}
-
-int TextEdit::get_h_scroll() const {
- return h_scroll->get_value();
-}
-
-void TextEdit::set_h_scroll(int p_scroll) {
- if (p_scroll < 0) {
- p_scroll = 0;
- }
- h_scroll->set_value(p_scroll);
-}
-
-void TextEdit::set_smooth_scroll_enabled(bool p_enable) {
- v_scroll->set_smooth_scroll_enabled(p_enable);
- smooth_scroll_enabled = p_enable;
-}
-
-bool TextEdit::is_smooth_scroll_enabled() const {
- return smooth_scroll_enabled;
-}
-
-void TextEdit::set_v_scroll_speed(float p_speed) {
- v_scroll_speed = p_speed;
-}
-
-float TextEdit::get_v_scroll_speed() const {
- return v_scroll_speed;
-}
-
String TextEdit::get_word_at_pos(const Vector2 &p_pos) const {
int row, col;
_get_mouse_pos(p_pos, row, col);
@@ -4748,30 +4548,6 @@ void TextEdit::insert_at(const String &p_text, int at) {
}
}
-void TextEdit::set_draw_minimap(bool p_draw) {
- if (draw_minimap != p_draw) {
- draw_minimap = p_draw;
- _update_wrap_at_column();
- }
- update();
-}
-
-bool TextEdit::is_drawing_minimap() const {
- return draw_minimap;
-}
-
-void TextEdit::set_minimap_width(int p_minimap_width) {
- if (minimap_width != p_minimap_width) {
- minimap_width = p_minimap_width;
- _update_wrap_at_column();
- }
- update();
-}
-
-int TextEdit::get_minimap_width() const {
- return minimap_width;
-}
-
void TextEdit::set_highlight_current_line(bool p_enabled) {
highlight_current_line = p_enabled;
update();
@@ -5023,7 +4799,6 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_count"), &TextEdit::get_line_count);
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_visible_line_count"), &TextEdit::get_total_visible_rows);
ClassDB::bind_method(D_METHOD("set_line", "line", "new_text"), &TextEdit::set_line);
ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override", "parser"), &TextEdit::set_structured_text_bidi_override);
@@ -5031,8 +4806,6 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override_options", "args"), &TextEdit::set_structured_text_bidi_override_options);
ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override_options"), &TextEdit::get_structured_text_bidi_override_options);
- ClassDB::bind_method(D_METHOD("center_viewport_to_caret"), &TextEdit::center_viewport_to_caret);
-
ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &TextEdit::set_context_menu_enabled);
ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &TextEdit::is_context_menu_enabled);
ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled", "enable"), &TextEdit::set_shortcut_keys_enabled);
@@ -5163,6 +4936,51 @@ void TextEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_line_wrapped_text", "line"), &TextEdit::get_line_wrapped_text);
+ /* Viewport. */
+ // Scolling.
+ 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", "value"), &TextEdit::set_v_scroll);
+ ClassDB::bind_method(D_METHOD("get_v_scroll"), &TextEdit::get_v_scroll);
+
+ ClassDB::bind_method(D_METHOD("set_h_scroll", "value"), &TextEdit::set_h_scroll);
+ ClassDB::bind_method(D_METHOD("get_h_scroll"), &TextEdit::get_h_scroll);
+
+ ClassDB::bind_method(D_METHOD("set_scroll_past_end_of_file_enabled", "enable"), &TextEdit::set_scroll_past_end_of_file_enabled);
+ ClassDB::bind_method(D_METHOD("is_scroll_past_end_of_file_enabled"), &TextEdit::is_scroll_past_end_of_file_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_v_scroll_speed", "speed"), &TextEdit::set_v_scroll_speed);
+ ClassDB::bind_method(D_METHOD("get_v_scroll_speed"), &TextEdit::get_v_scroll_speed);
+
+ ClassDB::bind_method(D_METHOD("get_scroll_pos_for_line", "line", "wrap_index"), &TextEdit::get_scroll_pos_for_line, DEFVAL(0));
+
+ // Visible lines.
+ ClassDB::bind_method(D_METHOD("set_line_as_first_visible", "line", "wrap_index"), &TextEdit::set_line_as_first_visible, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_first_visible_line"), &TextEdit::get_first_visible_line);
+
+ ClassDB::bind_method(D_METHOD("set_line_as_center_visible", "line", "wrap_index"), &TextEdit::set_line_as_center_visible, DEFVAL(0));
+
+ ClassDB::bind_method(D_METHOD("set_line_as_last_visible", "line", "wrap_index"), &TextEdit::set_line_as_last_visible, DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("get_last_full_visible_line"), &TextEdit::get_last_full_visible_line);
+ ClassDB::bind_method(D_METHOD("get_last_full_visible_line_wrap_index"), &TextEdit::get_last_full_visible_line_wrap_index);
+
+ ClassDB::bind_method(D_METHOD("get_visible_line_count"), &TextEdit::get_visible_line_count);
+ ClassDB::bind_method(D_METHOD("get_total_visible_line_count"), &TextEdit::get_total_visible_line_count);
+
+ // Auto adjust
+ ClassDB::bind_method(D_METHOD("adjust_viewport_to_caret"), &TextEdit::adjust_viewport_to_caret);
+ ClassDB::bind_method(D_METHOD("center_viewport_to_caret"), &TextEdit::center_viewport_to_caret);
+
+ // Minimap
+ ClassDB::bind_method(D_METHOD("draw_minimap", "draw"), &TextEdit::set_draw_minimap);
+ ClassDB::bind_method(D_METHOD("is_drawing_minimap"), &TextEdit::is_drawing_minimap);
+
+ ClassDB::bind_method(D_METHOD("set_minimap_width", "width"), &TextEdit::set_minimap_width);
+ ClassDB::bind_method(D_METHOD("get_minimap_width"), &TextEdit::get_minimap_width);
+
+ ClassDB::bind_method(D_METHOD("get_minimap_visible_lines"), &TextEdit::get_minimap_visible_lines);
+
/* Syntax Highlighting. */
ClassDB::bind_method(D_METHOD("set_syntax_highlighter", "syntax_highlighter"), &TextEdit::set_syntax_highlighter);
ClassDB::bind_method(D_METHOD("get_syntax_highlighter"), &TextEdit::get_syntax_highlighter);
@@ -5210,24 +5028,10 @@ void TextEdit::_bind_methods() {
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);
- ClassDB::bind_method(D_METHOD("get_v_scroll_speed"), &TextEdit::get_v_scroll_speed);
- ClassDB::bind_method(D_METHOD("set_v_scroll", "value"), &TextEdit::set_v_scroll);
- ClassDB::bind_method(D_METHOD("get_v_scroll"), &TextEdit::get_v_scroll);
- ClassDB::bind_method(D_METHOD("set_h_scroll", "value"), &TextEdit::set_h_scroll);
- ClassDB::bind_method(D_METHOD("get_h_scroll"), &TextEdit::get_h_scroll);
-
ClassDB::bind_method(D_METHOD("menu_option", "option"), &TextEdit::menu_option);
ClassDB::bind_method(D_METHOD("get_menu"), &TextEdit::get_menu);
ClassDB::bind_method(D_METHOD("is_menu_visible"), &TextEdit::is_menu_visible);
- ClassDB::bind_method(D_METHOD("draw_minimap", "draw"), &TextEdit::set_draw_minimap);
- ClassDB::bind_method(D_METHOD("is_drawing_minimap"), &TextEdit::is_drawing_minimap);
- ClassDB::bind_method(D_METHOD("set_minimap_width", "width"), &TextEdit::set_minimap_width);
- ClassDB::bind_method(D_METHOD("get_minimap_width"), &TextEdit::get_minimap_width);
-
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
@@ -5243,6 +5047,7 @@ void TextEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_past_end_of_file"), "set_scroll_past_end_of_file_enabled", "is_scroll_past_end_of_file_enabled");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "v_scroll_speed"), "set_v_scroll_speed", "get_v_scroll_speed");
ADD_PROPERTY(PropertyInfo(Variant::INT, "wrap_mode", PROPERTY_HINT_ENUM, "None,Boundary"), "set_line_wrapping_mode", "get_line_wrapping_mode");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "scroll_vertical"), "set_v_scroll", "get_v_scroll");
@@ -5749,6 +5554,266 @@ void TextEdit::_update_caret_wrap_offset() {
set_line_as_first_visible(caret.line_ofs, caret.wrap_ofs);
}
+/* Viewport. */
+void TextEdit::_update_scrollbars() {
+ Size2 size = get_size();
+ Size2 hmin = h_scroll->get_combined_minimum_size();
+ Size2 vmin = v_scroll->get_combined_minimum_size();
+
+ v_scroll->set_begin(Point2(size.width - vmin.width, cache.style_normal->get_margin(SIDE_TOP)));
+ v_scroll->set_end(Point2(size.width, size.height - cache.style_normal->get_margin(SIDE_TOP) - cache.style_normal->get_margin(SIDE_BOTTOM)));
+
+ h_scroll->set_begin(Point2(0, size.height - hmin.height));
+ h_scroll->set_end(Point2(size.width - vmin.width, size.height));
+
+ int visible_rows = get_visible_line_count();
+ int total_rows = get_total_visible_line_count();
+ if (scroll_past_end_of_file_enabled) {
+ total_rows += visible_rows - 1;
+ }
+
+ int visible_width = size.width - cache.style_normal->get_minimum_size().width;
+ int total_width = text.get_max_width(true) + vmin.x + gutters_width + gutter_padding;
+
+ if (draw_minimap) {
+ total_width += minimap_width;
+ }
+
+ updating_scrolls = true;
+
+ if (total_rows > visible_rows) {
+ v_scroll->show();
+ v_scroll->set_max(total_rows + _get_visible_lines_offset());
+ v_scroll->set_page(visible_rows + _get_visible_lines_offset());
+ if (smooth_scroll_enabled) {
+ v_scroll->set_step(0.25);
+ } else {
+ v_scroll->set_step(1);
+ }
+ set_v_scroll(get_v_scroll());
+
+ } else {
+ caret.line_ofs = 0;
+ caret.wrap_ofs = 0;
+ v_scroll->set_value(0);
+ v_scroll->hide();
+ }
+
+ if (total_width > visible_width && get_line_wrapping_mode() == LineWrappingMode::LINE_WRAPPING_NONE) {
+ h_scroll->show();
+ h_scroll->set_max(total_width);
+ h_scroll->set_page(visible_width);
+ if (caret.x_ofs > (total_width - visible_width)) {
+ caret.x_ofs = (total_width - visible_width);
+ }
+ if (fabs(h_scroll->get_value() - (double)caret.x_ofs) >= 1) {
+ h_scroll->set_value(caret.x_ofs);
+ }
+
+ } else {
+ caret.x_ofs = 0;
+ h_scroll->set_value(0);
+ h_scroll->hide();
+ }
+
+ updating_scrolls = false;
+}
+
+void TextEdit::_v_scroll_input() {
+ scrolling = false;
+ minimap_clicked = false;
+}
+
+void TextEdit::_scroll_moved(double p_to_val) {
+ if (updating_scrolls) {
+ return;
+ }
+
+ if (h_scroll->is_visible_in_tree()) {
+ caret.x_ofs = h_scroll->get_value();
+ }
+ if (v_scroll->is_visible_in_tree()) {
+ // Set line ofs and wrap ofs.
+ int v_scroll_i = floor(get_v_scroll());
+ int sc = 0;
+ int n_line;
+ for (n_line = 0; n_line < text.size(); n_line++) {
+ if (!_is_line_hidden(n_line)) {
+ sc++;
+ sc += get_line_wrap_count(n_line);
+ if (sc > v_scroll_i) {
+ break;
+ }
+ }
+ }
+ n_line = MIN(n_line, text.size() - 1);
+ int line_wrap_amount = get_line_wrap_count(n_line);
+ int wi = line_wrap_amount - (sc - v_scroll_i - 1);
+ wi = CLAMP(wi, 0, line_wrap_amount);
+
+ caret.line_ofs = n_line;
+ caret.wrap_ofs = wi;
+ }
+ update();
+}
+
+double TextEdit::_get_visible_lines_offset() const {
+ double total = _get_control_height();
+ total /= (double)get_row_height();
+ total = total - floor(total);
+ total = -CLAMP(total, 0.001, 1) + 1;
+ return total;
+}
+
+double TextEdit::_get_v_scroll_offset() const {
+ double val = get_v_scroll() - floor(get_v_scroll());
+ return CLAMP(val, 0, 1);
+}
+
+void TextEdit::_scroll_up(real_t p_delta) {
+ if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(-p_delta)) {
+ scrolling = false;
+ minimap_clicked = false;
+ }
+
+ if (scrolling) {
+ target_v_scroll = (target_v_scroll - p_delta);
+ } else {
+ target_v_scroll = (get_v_scroll() - p_delta);
+ }
+
+ if (smooth_scroll_enabled) {
+ if (target_v_scroll <= 0) {
+ target_v_scroll = 0;
+ }
+ if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) {
+ v_scroll->set_value(target_v_scroll);
+ } else {
+ scrolling = true;
+ set_physics_process_internal(true);
+ }
+ } else {
+ set_v_scroll(target_v_scroll);
+ }
+}
+
+void TextEdit::_scroll_down(real_t p_delta) {
+ if (scrolling && smooth_scroll_enabled && SGN(target_v_scroll - v_scroll->get_value()) != SGN(p_delta)) {
+ scrolling = false;
+ minimap_clicked = false;
+ }
+
+ if (scrolling) {
+ target_v_scroll = (target_v_scroll + p_delta);
+ } else {
+ target_v_scroll = (get_v_scroll() + p_delta);
+ }
+
+ if (smooth_scroll_enabled) {
+ int max_v_scroll = round(v_scroll->get_max() - v_scroll->get_page());
+ if (target_v_scroll > max_v_scroll) {
+ target_v_scroll = max_v_scroll;
+ }
+ if (Math::abs(target_v_scroll - v_scroll->get_value()) < 1.0) {
+ v_scroll->set_value(target_v_scroll);
+ } else {
+ scrolling = true;
+ set_physics_process_internal(true);
+ }
+ } else {
+ set_v_scroll(target_v_scroll);
+ }
+}
+
+void TextEdit::_scroll_lines_up() {
+ scrolling = false;
+ minimap_clicked = false;
+
+ // Adjust the vertical scroll.
+ set_v_scroll(get_v_scroll() - 1);
+
+ // Adjust the caret to viewport.
+ if (!selection.active) {
+ int cur_line = caret.line;
+ int cur_wrap = get_caret_wrap_index();
+ int last_vis_line = get_last_full_visible_line();
+ int last_vis_wrap = get_last_full_visible_line_wrap_index();
+
+ if (cur_line > last_vis_line || (cur_line == last_vis_line && cur_wrap > last_vis_wrap)) {
+ set_caret_line(last_vis_line, false, false, last_vis_wrap);
+ }
+ }
+}
+
+void TextEdit::_scroll_lines_down() {
+ scrolling = false;
+ minimap_clicked = false;
+
+ // Adjust the vertical scroll.
+ set_v_scroll(get_v_scroll() + 1);
+
+ // Adjust the caret to viewport.
+ if (!selection.active) {
+ int cur_line = caret.line;
+ int cur_wrap = get_caret_wrap_index();
+ int first_vis_line = get_first_visible_line();
+ int first_vis_wrap = caret.wrap_ofs;
+
+ if (cur_line < first_vis_line || (cur_line == first_vis_line && cur_wrap < first_vis_wrap)) {
+ set_caret_line(first_vis_line, false, false, first_vis_wrap);
+ }
+ }
+}
+
+// Minimap
+void TextEdit::_update_minimap_click() {
+ Point2 mp = _get_local_mouse_pos();
+
+ int xmargin_end = get_size().width - cache.style_normal->get_margin(SIDE_RIGHT);
+ if (!dragging_minimap && (mp.x < xmargin_end - minimap_width || mp.y > xmargin_end)) {
+ minimap_clicked = false;
+ return;
+ }
+ minimap_clicked = true;
+ dragging_minimap = true;
+
+ int row;
+ _get_minimap_mouse_row(Point2i(mp.x, mp.y), row);
+
+ if (row >= get_first_visible_line() && (row < get_last_full_visible_line() || row >= (text.size() - 1))) {
+ minimap_scroll_ratio = v_scroll->get_as_ratio();
+ minimap_scroll_click_pos = mp.y;
+ can_drag_minimap = true;
+ return;
+ }
+
+ int wi;
+ int first_line = row - num_lines_from_rows(row, 0, -get_visible_line_count() / 2, wi) + 1;
+ double delta = get_scroll_pos_for_line(first_line, wi) - get_v_scroll();
+ if (delta < 0) {
+ _scroll_up(-delta);
+ } else {
+ _scroll_down(delta);
+ }
+}
+
+void TextEdit::_update_minimap_drag() {
+ if (!can_drag_minimap) {
+ return;
+ }
+
+ int control_height = _get_control_height();
+ int scroll_height = v_scroll->get_max() * (minimap_char_size.y + minimap_line_spacing);
+ if (control_height > scroll_height) {
+ control_height = scroll_height;
+ }
+
+ Point2 mp = _get_local_mouse_pos();
+
+ double diff = (mp.y - minimap_scroll_click_pos) / control_height;
+ v_scroll->set_as_ratio(minimap_scroll_ratio + diff);
+}
+
TextEdit::TextEdit() {
clear();
set_focus_mode(FOCUS_ALL);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index ec5017cef87..c7829fcc1c5 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -280,6 +280,53 @@ private:
void _update_caret_wrap_offset();
+ /* Viewport. */
+ HScrollBar *h_scroll;
+ VScrollBar *v_scroll;
+
+ bool scroll_past_end_of_file_enabled = false;
+
+ // Smooth scrolling.
+ bool smooth_scroll_enabled = false;
+ float target_v_scroll = 0.0;
+ float v_scroll_speed = 80.0;
+
+ // Scrolling.
+ bool scrolling = false;
+ bool updating_scrolls = false;
+
+ void _update_scrollbars();
+
+ void _v_scroll_input();
+ void _scroll_moved(double p_to_val);
+
+ double _get_visible_lines_offset() const;
+ double _get_v_scroll_offset() const;
+
+ void _scroll_up(real_t p_delta);
+ void _scroll_down(real_t p_delta);
+
+ void _scroll_lines_up();
+ void _scroll_lines_down();
+
+ // Minimap
+ bool draw_minimap = false;
+
+ int minimap_width = 80;
+ Point2 minimap_char_size = Point2(1, 2);
+ int minimap_line_spacing = 1;
+
+ // minimap scroll
+ bool minimap_clicked = false;
+ bool dragging_minimap = false;
+ bool can_drag_minimap = false;
+
+ double minimap_scroll_ratio = 0.0;
+ double minimap_scroll_click_pos = 0.0;
+
+ void _update_minimap_click();
+ void _update_minimap_drag();
+
/* Syntax highlighting. */
Map syntax_highlighting_cache;
@@ -343,29 +390,11 @@ private:
bool draw_spaces = false;
bool text_changed_dirty = false;
bool undo_enabled = true;
- bool draw_minimap = false;
- int minimap_width = 80;
- Point2 minimap_char_size = Point2(1, 2);
- int minimap_line_spacing = 1;
bool highlight_all_occurrences = false;
- bool scroll_past_end_of_file_enabled = false;
bool highlight_current_line = false;
- bool smooth_scroll_enabled = false;
- bool scrolling = false;
- bool dragging_minimap = false;
- bool can_drag_minimap = false;
- bool minimap_clicked = false;
- double minimap_scroll_ratio = 0.0;
- double minimap_scroll_click_pos = 0.0;
- float target_v_scroll = 0.0;
- float v_scroll_speed = 80.0;
-
Timer *idle_detect;
- HScrollBar *h_scroll;
- VScrollBar *v_scroll;
- bool updating_scrolls = false;
Object *tooltip_obj = nullptr;
StringName tooltip_func;
@@ -382,37 +411,9 @@ private:
bool shortcut_keys_enabled = true;
bool virtual_keyboard_enabled = true;
- int get_visible_rows() const;
- int get_total_visible_rows() const;
-
- int _get_minimap_visible_rows() const;
-
- double get_scroll_pos_for_line(int p_line, int p_wrap_index = 0) const;
- void set_line_as_first_visible(int p_line, int p_wrap_index = 0);
- void set_line_as_center_visible(int p_line, int p_wrap_index = 0);
- void set_line_as_last_visible(int p_line, int p_wrap_index = 0);
- int get_first_visible_line() const;
- int get_last_full_visible_line() const;
- int get_last_full_visible_line_wrap_index() const;
- double get_visible_rows_offset() const;
- double get_v_scroll_offset() const;
-
int get_char_pos_for_line(int p_px, int p_line, int p_wrap_index = 0) const;
int get_column_x_offset_for_line(int p_char, int p_line) const;
- double get_scroll_line_diff() const;
- void _scroll_moved(double);
- void _update_scrollbars();
- void _v_scroll_input();
-
- void _update_minimap_click();
- void _update_minimap_drag();
- void _scroll_up(real_t p_delta);
- void _scroll_down(real_t p_delta);
-
- void _scroll_lines_up();
- void _scroll_lines_down();
-
Size2 get_minimum_size() const override;
int _get_control_height() const;
@@ -480,7 +481,6 @@ protected:
Color background_color;
int line_spacing = 1;
- int minimap_width = 0;
} cache;
virtual String get_tooltip(const Point2 &p_pos) const override;
@@ -608,6 +608,51 @@ public:
Vector get_line_wrapped_text(int p_line) const;
+ /* Viewport. */
+ //Scrolling.
+ void set_smooth_scroll_enabled(const bool p_enable);
+ bool is_smooth_scroll_enabled() const;
+
+ void set_scroll_past_end_of_file_enabled(const bool p_enabled);
+ bool is_scroll_past_end_of_file_enabled() const;
+
+ void set_v_scroll(double p_scroll);
+ double get_v_scroll() const;
+
+ void set_h_scroll(int p_scroll);
+ int get_h_scroll() const;
+
+ void set_v_scroll_speed(float p_speed);
+ float get_v_scroll_speed() const;
+
+ double get_scroll_pos_for_line(int p_line, int p_wrap_index = 0) const;
+
+ // Visible lines.
+ void set_line_as_first_visible(int p_line, int p_wrap_index = 0);
+ int get_first_visible_line() const;
+
+ void set_line_as_center_visible(int p_line, int p_wrap_index = 0);
+
+ void set_line_as_last_visible(int p_line, int p_wrap_index = 0);
+ int get_last_full_visible_line() const;
+ int get_last_full_visible_line_wrap_index() const;
+
+ int get_visible_line_count() const;
+ int get_total_visible_line_count() const;
+
+ // Auto Adjust
+ void adjust_viewport_to_caret();
+ void center_viewport_to_caret();
+
+ // Minimap
+ void set_draw_minimap(bool p_draw);
+ bool is_drawing_minimap() const;
+
+ void set_minimap_width(int p_minimap_width);
+ int get_minimap_width() const;
+
+ int get_minimap_visible_lines() const;
+
/* Syntax Highlighting. */
Ref get_syntax_highlighter();
void set_syntax_highlighter(Ref p_syntax_highlighter);
@@ -749,14 +794,6 @@ public:
int get_indent_level(int p_line) const;
int get_first_non_whitespace_column(int p_line) const;
- inline void set_scroll_pass_end_of_file(bool p_enabled) {
- scroll_past_end_of_file_enabled = p_enabled;
- update();
- }
-
- void adjust_viewport_to_caret();
- void center_viewport_to_caret();
-
void clear();
void swap_lines(int line1, int line2);
@@ -784,18 +821,6 @@ public:
void set_draw_spaces(bool p_draw);
bool is_drawing_spaces() const;
- double get_v_scroll() const;
- void set_v_scroll(double p_scroll);
-
- int get_h_scroll() const;
- void set_h_scroll(int p_scroll);
-
- void set_smooth_scroll_enabled(bool p_enable);
- bool is_smooth_scroll_enabled() const;
-
- void set_v_scroll_speed(float p_speed);
- float get_v_scroll_speed() const;
-
uint32_t get_version() const;
uint32_t get_saved_version() const;
void tag_saved_version();
@@ -805,12 +830,6 @@ public:
void set_highlight_current_line(bool p_enabled);
bool is_highlight_current_line_enabled() const;
- void set_draw_minimap(bool p_draw);
- bool is_drawing_minimap() const;
-
- void set_minimap_width(int p_minimap_width);
- int get_minimap_width() const;
-
void set_tooltip_request_func(Object *p_obj, const StringName &p_function, const Variant &p_udata);
void set_context_menu_enabled(bool p_enable);