diff options
-rw-r--r-- | editor/code_editor.cpp | 1 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.cpp | 160 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.h | 3 | ||||
-rw-r--r-- | scene/gui/text_edit.cpp | 329 | ||||
-rw-r--r-- | scene/gui/text_edit.h | 11 |
5 files changed, 310 insertions, 194 deletions
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index d43ec6d750..c7012a0c14 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1098,6 +1098,7 @@ void CodeTextEditor::update_editor_settings() { text_editor->cursor_set_blink_enabled(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink")); text_editor->cursor_set_blink_speed(EditorSettings::get_singleton()->get("text_editor/cursor/caret_blink_speed")); text_editor->set_draw_breakpoint_gutter(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_breakpoint_gutter")); + text_editor->set_hiding_enabled(EditorSettings::get_singleton()->get("text_editor/line_numbers/code_folding")); text_editor->set_draw_fold_gutter(EditorSettings::get_singleton()->get("text_editor/line_numbers/code_folding")); text_editor->cursor_set_block_mode(EditorSettings::get_singleton()->get("text_editor/cursor/block_caret")); text_editor->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/open_scripts/smooth_scrolling")); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 0fd0e578aa..214f24b386 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -518,7 +518,9 @@ void ScriptTextEditor::tag_saved_version() { } void ScriptTextEditor::goto_line(int p_line, bool p_with_error) { - code_editor->get_text_edit()->call_deferred("cursor_set_line", p_line); + TextEdit *tx = code_editor->get_text_edit(); + tx->unfold_line(p_line); + tx->call_deferred("cursor_set_line", p_line); } void ScriptTextEditor::ensure_focus() { @@ -790,39 +792,41 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c void ScriptTextEditor::_edit_option(int p_op) { + TextEdit *tx = code_editor->get_text_edit(); + switch (p_op) { case EDIT_UNDO: { - code_editor->get_text_edit()->undo(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + + tx->undo(); + tx->call_deferred("grab_focus"); } break; case EDIT_REDO: { - code_editor->get_text_edit()->redo(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + + tx->redo(); + tx->call_deferred("grab_focus"); } break; case EDIT_CUT: { - code_editor->get_text_edit()->cut(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + tx->cut(); + tx->call_deferred("grab_focus"); } break; case EDIT_COPY: { - code_editor->get_text_edit()->copy(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + tx->copy(); + tx->call_deferred("grab_focus"); } break; case EDIT_PASTE: { - code_editor->get_text_edit()->paste(); - code_editor->get_text_edit()->call_deferred("grab_focus"); + tx->paste(); + tx->call_deferred("grab_focus"); } break; case EDIT_SELECT_ALL: { - code_editor->get_text_edit()->select_all(); - code_editor->get_text_edit()->call_deferred("grab_focus"); - + tx->select_all(); + tx->call_deferred("grab_focus"); } break; case EDIT_MOVE_LINE_UP: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = script; if (scr.is_null()) return; @@ -841,8 +845,8 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == 0 || next_id < 0) return; - if (tx->is_line_hidden(next_id)) - tx->unfold_line(next_id); + tx->unfold_line(line_id); + tx->unfold_line(next_id); tx->swap_lines(line_id, next_id); tx->cursor_set_line(next_id); @@ -857,19 +861,17 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == 0 || next_id < 0) return; - if (tx->is_line_hidden(next_id)) - tx->unfold_line(next_id); + tx->unfold_line(line_id); + tx->unfold_line(next_id); tx->swap_lines(line_id, next_id); tx->cursor_set_line(next_id); } tx->end_complex_operation(); tx->update(); - } break; case EDIT_MOVE_LINE_DOWN: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -888,8 +890,8 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) return; - if (tx->is_folded(next_id) || tx->is_line_hidden(next_id)) - tx->unfold_line(next_id); + tx->unfold_line(line_id); + tx->unfold_line(next_id); tx->swap_lines(line_id, next_id); tx->cursor_set_line(next_id); @@ -904,8 +906,8 @@ void ScriptTextEditor::_edit_option(int p_op) { if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) return; - if (tx->is_folded(next_id) || tx->is_line_hidden(next_id)) - tx->unfold_line(next_id); + tx->unfold_line(line_id); + tx->unfold_line(next_id); tx->swap_lines(line_id, next_id); tx->cursor_set_line(next_id); @@ -916,7 +918,6 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_INDENT_LEFT: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -941,11 +942,9 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); //tx->deselect(); - } break; case EDIT_INDENT_RIGHT: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -962,11 +961,9 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); //tx->deselect(); - } break; case EDIT_DELETE_LINE: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -975,13 +972,12 @@ void ScriptTextEditor::_edit_option(int p_op) { int line = tx->cursor_get_line(); tx->set_line(tx->cursor_get_line(), ""); tx->backspace_at_cursor(); + tx->unfold_line(line); tx->cursor_set_line(line); tx->end_complex_operation(); - } break; case EDIT_CLONE_DOWN: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -1000,6 +996,7 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->begin_complex_operation(); for (int i = from_line; i <= to_line; i++) { + tx->unfold_line(i); if (i >= tx->get_line_count() - 1) { tx->set_line(i, tx->get_line(i) + "\n"); } @@ -1015,29 +1012,29 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); - } break; case EDIT_FOLD_LINE: { - TextEdit *tx = code_editor->get_text_edit(); tx->fold_line(tx->cursor_get_line()); tx->update(); } break; case EDIT_UNFOLD_LINE: { - TextEdit *tx = code_editor->get_text_edit(); tx->unfold_line(tx->cursor_get_line()); tx->update(); } break; + case EDIT_FOLD_ALL_LINES: { + + tx->fold_all_lines(); + tx->update(); + } break; case EDIT_UNFOLD_ALL_LINES: { - TextEdit *tx = code_editor->get_text_edit(); tx->unhide_all_lines(); tx->update(); } break; case EDIT_TOGGLE_COMMENT: { - TextEdit *tx = code_editor->get_text_edit(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; @@ -1086,62 +1083,65 @@ void ScriptTextEditor::_edit_option(int p_op) { tx->end_complex_operation(); tx->update(); //tx->deselect(); - } break; case EDIT_COMPLETE: { - code_editor->get_text_edit()->query_code_comple(); - + tx->query_code_comple(); } break; case EDIT_AUTO_INDENT: { - TextEdit *te = code_editor->get_text_edit(); - String text = te->get_text(); + String text = tx->get_text(); Ref<Script> scr = get_edited_script(); if (scr.is_null()) return; - te->begin_complex_operation(); + tx->begin_complex_operation(); int begin, end; - if (te->is_selection_active()) { - begin = te->get_selection_from_line(); - end = te->get_selection_to_line(); + if (tx->is_selection_active()) { + begin = tx->get_selection_from_line(); + end = tx->get_selection_to_line(); // ignore if the cursor is not past the first column - if (te->get_selection_to_column() == 0) { + if (tx->get_selection_to_column() == 0) { end--; } } else { begin = 0; - end = te->get_line_count() - 1; + end = tx->get_line_count() - 1; } scr->get_language()->auto_indent_code(text, begin, end); Vector<String> lines = text.split("\n"); for (int i = begin; i <= end; ++i) { - te->set_line(i, lines[i]); + tx->set_line(i, lines[i]); } - te->end_complex_operation(); - + tx->end_complex_operation(); } break; case EDIT_TRIM_TRAILING_WHITESAPCE: { + trim_trailing_whitespace(); } break; case EDIT_CONVERT_INDENT_TO_SPACES: { + convert_indent_to_spaces(); } break; case EDIT_CONVERT_INDENT_TO_TABS: { + convert_indent_to_tabs(); } break; case EDIT_PICK_COLOR: { + color_panel->popup(); } break; case EDIT_TO_UPPERCASE: { + _convert_case(UPPER); } break; case EDIT_TO_LOWERCASE: { + _convert_case(LOWER); } break; case EDIT_CAPITALIZE: { + _convert_case(CAPITALIZE); } break; case SEARCH_FIND: { @@ -1166,41 +1166,47 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case SEARCH_GOTO_LINE: { - goto_line_dialog->popup_find_line(code_editor->get_text_edit()); + goto_line_dialog->popup_find_line(tx); } break; case DEBUG_TOGGLE_BREAKPOINT: { - int line = code_editor->get_text_edit()->cursor_get_line(); - bool dobreak = !code_editor->get_text_edit()->is_line_set_as_breakpoint(line); - code_editor->get_text_edit()->set_line_as_breakpoint(line, dobreak); + + int line = tx->cursor_get_line(); + bool dobreak = !tx->is_line_set_as_breakpoint(line); + tx->set_line_as_breakpoint(line, dobreak); ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak); } break; case DEBUG_REMOVE_ALL_BREAKPOINTS: { + List<int> bpoints; - code_editor->get_text_edit()->get_breakpoints(&bpoints); + tx->get_breakpoints(&bpoints); for (List<int>::Element *E = bpoints.front(); E; E = E->next()) { int line = E->get(); - bool dobreak = !code_editor->get_text_edit()->is_line_set_as_breakpoint(line); - code_editor->get_text_edit()->set_line_as_breakpoint(line, dobreak); + bool dobreak = !tx->is_line_set_as_breakpoint(line); + tx->set_line_as_breakpoint(line, dobreak); ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak); } } case DEBUG_GOTO_NEXT_BREAKPOINT: { + List<int> bpoints; - code_editor->get_text_edit()->get_breakpoints(&bpoints); + tx->get_breakpoints(&bpoints); if (bpoints.size() <= 0) { return; } - int line = code_editor->get_text_edit()->cursor_get_line(); + int line = tx->cursor_get_line(); + // wrap around if (line >= bpoints[bpoints.size() - 1]) { - code_editor->get_text_edit()->cursor_set_line(bpoints[0]); + tx->unfold_line(bpoints[0]); + tx->cursor_set_line(bpoints[0]); } else { for (List<int>::Element *E = bpoints.front(); E; E = E->next()) { int bline = E->get(); if (bline > line) { - code_editor->get_text_edit()->cursor_set_line(bline); + tx->unfold_line(bline); + tx->cursor_set_line(bline); return; } } @@ -1208,21 +1214,24 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case DEBUG_GOTO_PREV_BREAKPOINT: { + List<int> bpoints; - code_editor->get_text_edit()->get_breakpoints(&bpoints); + tx->get_breakpoints(&bpoints); if (bpoints.size() <= 0) { return; } - int line = code_editor->get_text_edit()->cursor_get_line(); + int line = tx->cursor_get_line(); // wrap around if (line <= bpoints[0]) { - code_editor->get_text_edit()->cursor_set_line(bpoints[bpoints.size() - 1]); + tx->unfold_line(bpoints[bpoints.size() - 1]); + tx->cursor_set_line(bpoints[bpoints.size() - 1]); } else { for (List<int>::Element *E = bpoints.back(); E; E = E->prev()) { int bline = E->get(); if (bline < line) { - code_editor->get_text_edit()->cursor_set_line(bline); + tx->unfold_line(bline); + tx->cursor_set_line(bline); return; } } @@ -1231,9 +1240,10 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case HELP_CONTEXTUAL: { - String text = code_editor->get_text_edit()->get_selection_text(); + + String text = tx->get_selection_text(); if (text == "") - text = code_editor->get_text_edit()->get_word_under_cursor(); + text = tx->get_word_under_cursor(); if (text != "") { emit_signal("request_help_search", text); } @@ -1420,8 +1430,8 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { bool have_selection = (tx->get_selection_text().length() > 0); bool have_color = (tx->get_word_at_pos(mpos) == "Color"); int fold_state = 0; - if (row > 0 && row < tx->get_line_count() - 1) - fold_state = tx->can_fold(row) ? 1 : tx->is_folded(row) ? 2 : 0; + bool can_fold = tx->can_fold(row); + bool is_folded = tx->is_folded(row); if (have_color) { String line = tx->get_line(row); @@ -1452,7 +1462,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { have_color = false; } } - _make_context_menu(have_selection, have_color, fold_state); + _make_context_menu(have_selection, have_color, can_fold, is_folded); } } } @@ -1471,7 +1481,7 @@ void ScriptTextEditor::_color_changed(const Color &p_color) { code_editor->get_text_edit()->set_line(color_line, new_line); } -void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, int p_fold_state) { +void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_can_fold, bool p_is_folded) { context_menu->clear(); if (p_selection) { @@ -1491,10 +1501,10 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, int p_ context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); } - if (p_fold_state == 1) { + if (p_can_fold) { // can fold context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE); - } else if (p_fold_state == 2) { + } else if (p_is_folded) { // can unfold context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE); } @@ -1562,6 +1572,7 @@ ScriptTextEditor::ScriptTextEditor() { edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES); edit_menu->get_popup()->add_separator(); @@ -1643,6 +1654,7 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD | KEY_B); ED_SHORTCUT("script_text_editor/fold_line", TTR("Fold Line"), KEY_MASK_ALT | KEY_LEFT); ED_SHORTCUT("script_text_editor/unfold_line", TTR("Unfold Line"), KEY_MASK_ALT | KEY_RIGHT); + ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), 0); ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), 0); #ifdef OSX_ENABLED ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CTRL | KEY_SPACE); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 8b353d4179..722015ef3e 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -93,6 +93,7 @@ class ScriptTextEditor : public ScriptEditorBase { EDIT_CAPITALIZE, EDIT_FOLD_LINE, EDIT_UNFOLD_LINE, + EDIT_FOLD_ALL_LINES, EDIT_UNFOLD_ALL_LINES, SEARCH_FIND, SEARCH_FIND_NEXT, @@ -121,7 +122,7 @@ protected: static void _bind_methods(); void _edit_option(int p_op); - void _make_context_menu(bool p_selection, bool p_color, int p_fold_state); + void _make_context_menu(bool p_selection, bool p_color, bool p_can_fold, bool p_is_folded); void _text_edit_gui_input(const Ref<InputEvent> &ev); void _color_changed(const Color &p_color); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 1ffbac05de..a1ecf291c1 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -300,9 +300,9 @@ void TextEdit::_update_scrollbars() { int visible_rows = get_visible_rows(); int num_rows = MAX(visible_rows, num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(visible_rows, text.size() - 1 - cursor.line_ofs))); - int total_rows = text.size(); + int total_rows = (is_hiding_enabled() ? get_total_unhidden_rows() : text.size()); if (scroll_past_end_of_file_enabled) { - total_rows += get_visible_rows() - 1; + total_rows += visible_rows - 1; } int vscroll_pixels = v_scroll->get_combined_minimum_size().width; @@ -347,19 +347,18 @@ void TextEdit::_update_scrollbars() { v_scroll->show(); v_scroll->set_max(total_rows); - v_scroll->set_page(num_rows); + v_scroll->set_page(visible_rows); if (smooth_scroll_enabled) { v_scroll->set_step(0.25); } else { v_scroll->set_step(1); } - if (fabs(v_scroll->get_value() - (double)cursor.line_ofs) >= 1) { - v_scroll->set_value(cursor.line_ofs); - } - + update_line_scroll_pos(); } else { cursor.line_ofs = 0; + line_scroll_pos = 0; + v_scroll->set_value(0); v_scroll->hide(); } @@ -794,6 +793,7 @@ void TextEdit::_notification(int p_what) { String highlighted_text = get_selection_text(); String line_num_padding = line_numbers_zero_padded ? "0" : " "; + update_line_scroll_pos(); int line = cursor.line_ofs - 1; for (int i = 0; i < visible_rows; i++) { @@ -819,7 +819,7 @@ void TextEdit::_notification(int p_what) { int char_ofs = 0; int ofs_y = (i * get_row_height() + cache.line_spacing / 2); if (smooth_scroll_enabled) { - ofs_y -= (v_scroll->get_value() - cursor.line_ofs) * get_row_height(); + ofs_y -= (v_scroll->get_value() - get_line_scroll_pos()) * get_row_height(); } bool prev_is_char = false; @@ -882,18 +882,18 @@ void TextEdit::_notification(int p_what) { } } - // draw fold marker + // draw fold markers if (draw_fold_gutter) { - int horizontal_gap = (cache.breakpoint_gutter_width * 30) / 100; + int horizontal_gap = (cache.fold_gutter_width * 30) / 100; int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.line_number_w; if (is_folded(line)) { - int xofs = -cache.can_fold_icon->get_width() / 2 - horizontal_gap; + int xofs = horizontal_gap - (cache.can_fold_icon->get_width()) / 2; int yofs = (get_row_height() - cache.folded_icon->get_height()) / 2; - cache.folded_icon->draw(ci, Point2(gutter_left + xofs, ofs_y + yofs)); + cache.folded_icon->draw(ci, Point2(gutter_left + xofs, ofs_y + yofs), Color(0.8f, 0.8f, 0.8f, 0.8f)); } else if (can_fold(line)) { - int xofs = (cache.fold_gutter_width - cache.can_fold_icon->get_width()) / 2; + int xofs = -cache.can_fold_icon->get_width() / 2 - horizontal_gap + 3; int yofs = (get_row_height() - cache.can_fold_icon->get_height()) / 2; - cache.can_fold_icon->draw(ci, Point2(gutter_left + xofs, ofs_y + yofs)); + cache.can_fold_icon->draw(ci, Point2(gutter_left + xofs, ofs_y + yofs), Color(0.8f, 0.8f, 0.8f, 0.8f)); } } @@ -1236,6 +1236,10 @@ void TextEdit::_notification(int p_what) { } char_ofs += char_w; + + if (j == str.length() - 1 && is_folded(line)) { + cache.folded_eol_icon->draw(ci, Point2(char_ofs + char_margin, ofs_y), Color(1, 1, 1, 1), true); + } } if (cursor.column == str.length() && cursor.line == line && (char_ofs + char_margin) >= xmargin_beg) { @@ -1697,21 +1701,15 @@ 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(MARGIN_TOP); rows /= get_row_height(); - int row = cursor.line_ofs + (rows + (v_scroll->get_value() - cursor.line_ofs)); + int lsp = get_line_scroll_pos(true); + int row = cursor.line_ofs + (rows + (v_scroll->get_value() - lsp)); if (is_hiding_enabled()) { // row will be offset by the hidden rows - int f_ofs = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(rows, text.size() - 1 - cursor.line_ofs)); - row = cursor.line_ofs + (f_ofs + (v_scroll->get_value() - cursor.line_ofs)); - // set row to spot below folded area - while (is_line_hidden(row)) { - row++; - if (row >= text.size() - 1) - break; - } + int f_ofs = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(rows + 1, text.size() - cursor.line_ofs)) - 1; + row = cursor.line_ofs + (f_ofs + (v_scroll->get_value() - lsp)); + row = CLAMP(row, 0, text.size() - num_lines_from(text.size() - 1, -1)); } - if (rows <= 1) - row = CLAMP(cursor.line_ofs, 0, text.size() - 1); if (row < 0) row = 0; //todo @@ -1784,13 +1782,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { target_v_scroll = (v_scroll->get_value() - scroll_factor); } - int hidden_lines = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), -(int)scroll_factor) - scroll_factor - 1; - if (hiding_enabled && hidden_lines > 0) { - target_v_scroll -= hidden_lines; - if (smooth_scroll_enabled) - v_scroll->set_value(v_scroll->get_value() - hidden_lines); - } - if (smooth_scroll_enabled) { if (target_v_scroll <= 0) { target_v_scroll = 0; @@ -1809,19 +1800,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { target_v_scroll = (v_scroll->get_value() + scroll_factor); } - // todo fix scrolling down over large hidden sections - int hidden_lines = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MAX((int)scroll_factor, 1)) - scroll_factor - 1; - if (hiding_enabled && hidden_lines > 0) { // && !is_line_hidden(cursor.line_ofs)) { - target_v_scroll += hidden_lines; - if (smooth_scroll_enabled) { - v_scroll->set_value(v_scroll->get_value() + hidden_lines); - } - } - if (smooth_scroll_enabled) { - int max_v_scroll = get_line_count() - 1; + int max_v_scroll = get_total_unhidden_rows(); if (!scroll_past_end_of_file_enabled) { - max_v_scroll -= num_lines_from(text.size() - 1, -get_visible_rows()) - 1; + max_v_scroll -= get_visible_rows(); + max_v_scroll = CLAMP(max_v_scroll, 0, get_total_unhidden_rows()); } if (target_v_scroll > max_v_scroll) { @@ -1844,6 +1827,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _reset_caret_blink_timer(); int row, col; + update_line_scroll_pos(); _get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col); if (mb->get_command() && highlighted_word != String()) { @@ -1867,13 +1851,22 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.line_number_w; - if (mb->get_position().x > gutter_left - 3 && mb->get_position().x <= gutter_left + cache.fold_gutter_width + 3) { + if (mb->get_position().x > gutter_left - 6 && mb->get_position().x <= gutter_left + cache.fold_gutter_width - 3) { if (is_folded(row)) { unfold_line(row); } else if (can_fold(row)) { fold_line(row); } - //emit_signal("fold_toggled", row); + return; + } + } + + // unfold on folded icon click + if (is_folded(row)) { + int line_width = text.get_line_width(row); + line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width - cursor.x_ofs; + if (mb->get_position().x > line_width - 3 && mb->get_position().x <= line_width + cache.folded_eol_icon->get_width() + 3) { + unfold_line(row); return; } } @@ -2124,7 +2117,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { _confirm_completion(); accept_event(); - emit_signal("request_completion"); return; } @@ -2537,9 +2529,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else if (cursor.column == 0) { if (cursor.line > 0) { - if (is_line_hidden(cursor.line - 1)) - unfold_line(cursor.line - 1); - cursor_set_line(cursor.line - 1); + cursor_set_line(cursor.line - num_lines_from(CLAMP(cursor.line - 1, 0, text.size() - 1), -1)); cursor_set_column(text[cursor.line].length()); } } else { @@ -2602,10 +2592,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { } else if (cursor.column == text[cursor.line].length()) { if (cursor.line < text.size() - 1) { - if (is_folded(cursor.line + 1)) - unfold_line(cursor.line + 1); - cursor_set_line(cursor.line + 1); - + cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false); cursor_set_column(0); } } else { @@ -2646,7 +2633,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { cursor_set_line(0); else #endif - cursor_set_line(cursor_get_line() - num_lines_from(cursor.line - 1, -1)); + cursor_set_line(cursor_get_line() - num_lines_from(CLAMP(cursor.line - 1, 0, text.size() - 1), -1)); if (k->get_shift()) _post_shift_selection(); @@ -2683,7 +2670,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { cursor_set_line(text.size() - 1, true, false); else #endif - cursor_set_line(cursor_get_line() + num_lines_from(cursor.line + 1, 1)); + cursor_set_line(cursor_get_line() + num_lines_from(CLAMP(cursor.line + 1, 0, text.size() - 1), 1), true, false); if (k->get_shift()) _post_shift_selection(); @@ -3105,12 +3092,13 @@ void TextEdit::_scroll_lines_up() { // adjust the vertical scroll if (get_v_scroll() > 0) { - set_v_scroll(get_v_scroll() - num_lines_from(get_v_scroll(), -1)); + set_v_scroll(get_v_scroll() - 1); } // adjust the cursor - if (cursor_get_line() >= (get_visible_rows() + get_v_scroll()) && !selection.active) { - cursor_set_line((get_visible_rows() + get_v_scroll()) - 1, false, false); + int num_lines = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), get_visible_rows()) - 1; + if (cursor.line >= cursor.line_ofs + num_lines && !selection.active) { + cursor_set_line(cursor.line_ofs + num_lines, false, false); } } @@ -3118,19 +3106,20 @@ void TextEdit::_scroll_lines_down() { scrolling = false; // calculate the maximum vertical scroll position - int max_v_scroll = get_line_count() - 1; + int max_v_scroll = get_total_unhidden_rows(); if (!scroll_past_end_of_file_enabled) { - max_v_scroll -= get_visible_rows() - 1; + max_v_scroll -= get_visible_rows(); + max_v_scroll = CLAMP(max_v_scroll, 0, get_total_unhidden_rows()); } // adjust the vertical scroll if (get_v_scroll() < max_v_scroll) { - set_v_scroll(get_v_scroll() + num_lines_from(get_v_scroll(), 1)); + set_v_scroll(get_v_scroll() + 1); } // adjust the cursor - if ((cursor_get_line()) <= get_v_scroll() - 1 && !selection.active) { - cursor_set_line(get_v_scroll(), false, false); + if (cursor.line <= cursor.line_ofs - 1 && !selection.active) { + cursor_set_line(cursor.line_ofs, false, false); } } @@ -3391,11 +3380,58 @@ int TextEdit::get_visible_rows() const { return total; } +int TextEdit::get_total_unhidden_rows() const { + if (!is_hiding_enabled()) + return text.size(); + + int total_unhidden = 0; + for (int i = 0; i < text.size(); i++) { + if (!text.is_hidden(i)) + total_unhidden++; + } + return total_unhidden; +} + +double TextEdit::get_line_scroll_pos(bool p_recalculate) const { + + if (!is_hiding_enabled()) + return cursor.line_ofs; + if (!p_recalculate) + return line_scroll_pos; + + // count num unhidden lines to the cursor line ofs + double new_line_scroll_pos = 0; + int to = CLAMP(cursor.line_ofs, 0, text.size() - 1); + for (int i = 0; i < to; i++) { + if (!text.is_hidden(i)) + new_line_scroll_pos++; + } + return new_line_scroll_pos; +} + +void TextEdit::update_line_scroll_pos() { + + if (!is_hiding_enabled()) { + line_scroll_pos = cursor.line_ofs; + return; + } + + // count num unhidden lines to the cursor line ofs + double new_line_scroll_pos = 0; + int to = CLAMP(cursor.line_ofs, 0, text.size() - 1); + for (int i = 0; i < to; i++) { + if (!text.is_hidden(i)) + new_line_scroll_pos++; + } + line_scroll_pos = new_line_scroll_pos; +} + void TextEdit::adjust_viewport_to_cursor() { scrolling = false; - if (cursor.line_ofs > cursor.line) + if (cursor.line_ofs > cursor.line) { cursor.line_ofs = cursor.line; + } int visible_width = cache.size.width - cache.style_normal->get_minimum_size().width - cache.line_number_w - cache.breakpoint_gutter_width - cache.fold_gutter_width; if (v_scroll->is_visible_in_tree()) @@ -3405,16 +3441,19 @@ void TextEdit::adjust_viewport_to_cursor() { int visible_rows = get_visible_rows(); if (h_scroll->is_visible_in_tree()) visible_rows -= ((h_scroll->get_combined_minimum_size().height - 1) / get_row_height()); - int num_rows = num_lines_from(CLAMP(cursor.line_ofs, 0, text.size() - 1), MIN(visible_rows, text.size() - 1 - cursor.line_ofs)); - if (cursor.line >= (cursor.line_ofs + MAX(num_rows, visible_rows))) - cursor.line_ofs = cursor.line - MAX(num_lines_from(CLAMP(cursor.line, 0, text.size() - 1), -visible_rows), visible_rows); - if (cursor.line < cursor.line_ofs) + + // if the cursor is off the screen + if (cursor.line >= (cursor.line_ofs + MAX(num_rows, visible_rows))) { + cursor.line_ofs = cursor.line - (num_lines_from(CLAMP(cursor.line, 0, text.size() - 1), -visible_rows) - 1); + } + if (cursor.line < cursor.line_ofs) { cursor.line_ofs = cursor.line; + } - if (cursor.line_ofs + visible_rows > text.size() && !scroll_past_end_of_file_enabled) { - cursor.line_ofs = text.size() - MAX(num_lines_from(text.size() - 1, -visible_rows), visible_rows); - v_scroll->set_value(text.size() - MAX(num_lines_from(text.size() - 1, -visible_rows), visible_rows)); + // fixes deleting lines from moving the line ofs in a bad way + if (!scroll_past_end_of_file_enabled && get_total_unhidden_rows() > visible_rows && num_rows < visible_rows) { + cursor.line_ofs = text.size() - 1 - (num_lines_from(text.size() - 1, -visible_rows) - 1); } int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]); @@ -3425,6 +3464,8 @@ void TextEdit::adjust_viewport_to_cursor() { if (cursor_x < cursor.x_ofs) cursor.x_ofs = cursor_x; + update_line_scroll_pos(); + v_scroll->set_value(get_line_scroll_pos() + 1); update(); /* get_range()->set_max(text.size()); @@ -3455,7 +3496,6 @@ void TextEdit::center_viewport_to_cursor() { int max_ofs = text.size() - (scroll_past_end_of_file_enabled ? 1 : num_lines_from(text.size() - 1, -visible_rows)); cursor.line_ofs = CLAMP(cursor.line - num_lines_from(cursor.line - visible_rows / 2, -visible_rows / 2), 0, max_ofs); - int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]); if (cursor_x > (cursor.x_ofs + visible_width)) @@ -3464,6 +3504,9 @@ void TextEdit::center_viewport_to_cursor() { if (cursor_x < cursor.x_ofs) cursor.x_ofs = cursor_x; + update_line_scroll_pos(); + v_scroll->set_value(get_line_scroll_pos()); + update(); } @@ -3501,26 +3544,16 @@ void TextEdit::cursor_set_line(int p_row, bool p_adjust_viewport, bool p_can_be_ p_row = (int)text.size() - 1; if (!p_can_be_hidden) { - if (is_line_hidden(p_row)) { - WARN_PRINTS(("Cursor set to hidden line " + itos(p_row))); - // search in a direction until we are not in a hidden line anymore - bool search_down = (p_row == 0 || cursor.line < p_row) && p_row != text.size() - 1; - bool orig_search_down = search_down; - while (is_line_hidden(p_row)) { - if (search_down) - p_row++; - else - p_row--; - // hit end of file, change dir - if (p_row >= text.size() - 1) { - search_down = false; - if (orig_search_down == search_down) - break; - } - if (p_row <= 0) { - search_down = true; - if (orig_search_down == search_down) - break; + if (is_line_hidden(CLAMP(p_row, 0, text.size() - 1))) { + int move_down = num_lines_from(p_row, 1) - 1; + if (p_row + move_down <= text.size() - 1 && !is_line_hidden(p_row + move_down)) { + p_row += move_down; + } else { + int move_up = num_lines_from(p_row, -1) - 1; + if (p_row - move_up > 0 && !is_line_hidden(p_row - move_up)) { + p_row -= move_up; + } else { + WARN_PRINTS(("Cursor set to hidden line " + itos(p_row) + " and there are no nonhidden lines.")); } } } @@ -3594,8 +3627,11 @@ void TextEdit::_scroll_moved(double p_to_val) { if (h_scroll->is_visible_in_tree()) cursor.x_ofs = h_scroll->get_value(); - if (v_scroll->is_visible_in_tree()) - cursor.line_ofs = v_scroll->get_value(); + if (v_scroll->is_visible_in_tree()) { + double val = v_scroll->get_value(); + cursor.line_ofs = num_lines_from(0, (int)floor(val)) - 1; + line_scroll_pos = (int)floor(val); + } update(); } @@ -3685,9 +3721,42 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { return CURSOR_POINTING_HAND; int gutter = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width; - if ((completion_active && completion_rect.has_point(p_pos)) || p_pos.x < gutter) { + if ((completion_active && completion_rect.has_point(p_pos))) { + return CURSOR_ARROW; + } + if (p_pos.x < gutter) { + + int row, col; + _get_mouse_pos(p_pos, row, col); + int left_margin = cache.style_normal->get_margin(MARGIN_LEFT); + + // breakpoint icon + if (draw_breakpoint_gutter && p_pos.x > left_margin && p_pos.x <= left_margin + cache.breakpoint_gutter_width + 3) { + return CURSOR_POINTING_HAND; + } + + // fold icon + int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.line_number_w; + if (draw_fold_gutter && p_pos.x > gutter_left - 6 && p_pos.x <= gutter_left + cache.fold_gutter_width - 3) { + if (is_folded(row) || can_fold(row)) + return CURSOR_POINTING_HAND; + else + return CURSOR_ARROW; + } return CURSOR_ARROW; + } else { + int row, col; + _get_mouse_pos(p_pos, row, col); + // eol fold icon + if (is_folded(row)) { + int line_width = text.get_line_width(row); + line_width += cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width + cache.fold_gutter_width - cursor.x_ofs; + if (p_pos.x > line_width - 3 && p_pos.x <= line_width + cache.folded_eol_icon->get_width() + 3) { + return CURSOR_POINTING_HAND; + } + } } + return CURSOR_IBEAM; } @@ -3701,6 +3770,7 @@ void TextEdit::set_text(String p_text) { cursor.line = 0; cursor.x_ofs = 0; cursor.line_ofs = 0; + line_scroll_pos = 0; cursor.last_fit_x = 0; cursor_set_line(0); cursor_set_column(0); @@ -3786,6 +3856,7 @@ void TextEdit::_clear() { cursor.line = 0; cursor.x_ofs = 0; cursor.line_ofs = 0; + line_scroll_pos = 0; cursor.last_fit_x = 0; } @@ -3864,8 +3935,9 @@ void TextEdit::_update_caches() { cache.line_spacing = get_constant("line_spacing"); cache.row_height = cache.font->get_height() + cache.line_spacing; cache.tab_icon = get_icon("tab"); - cache.folded_icon = get_icon("Collapse", "EditorIcons"); - cache.can_fold_icon = get_icon("Forward", "EditorIcons"); + cache.folded_icon = get_icon("GuiTreeArrowRight", "EditorIcons"); + cache.can_fold_icon = get_icon("GuiTreeArrowDown", "EditorIcons"); + cache.folded_eol_icon = get_icon("GuiTabMenu", "EditorIcons"); text.set_font(cache.font); } @@ -4326,11 +4398,21 @@ bool TextEdit::is_line_hidden(int p_line) const { return text.is_hidden(p_line); } +void TextEdit::fold_all_lines() { + + for (int i = 0; i < text.size(); i++) { + fold_line(i); + } + _update_scrollbars(); + update(); +} + void TextEdit::unhide_all_lines() { for (int i = 0; i < text.size(); i++) { text.set_hidden(i, false); } + _update_scrollbars(); update(); } @@ -4377,9 +4459,7 @@ int TextEdit::get_whitespace_level(int p_line) const { } else if (text[p_line][i] == ' ') { whitespace_count++; } else if (text[p_line][i] == '#') { - if (whitespace_count != 0) { - break; - } + break; } else { break; } @@ -4392,14 +4472,14 @@ bool TextEdit::can_fold(int p_line) const { ERR_FAIL_INDEX_V(p_line, text.size(), false); if (!is_hiding_enabled()) return false; - if (!draw_fold_gutter) - return false; - if (p_line + 2 >= text.size()) + if (p_line + 1 >= text.size()) return false; if (text[p_line].size() == 0) return false; if (is_folded(p_line)) return false; + if (is_line_hidden(p_line)) + return false; int start_indent = get_whitespace_level(p_line); @@ -4434,6 +4514,7 @@ void TextEdit::fold_line(int p_line) { if (!can_fold(p_line)) return; + // hide lines below this one int start_indent = get_whitespace_level(p_line); for (int i = p_line + 1; i < text.size(); i++) { int cur_indent = get_whitespace_level(i); @@ -4447,13 +4528,27 @@ void TextEdit::fold_line(int p_line) { else break; } - if (is_line_hidden(cursor.line)) { - cursor_set_line(i, true, false); - } break; } } - adjust_viewport_to_cursor(); + + // fix selection + if (is_selection_active()) { + if (is_line_hidden(selection.from_line) && is_line_hidden(selection.to_line)) { + deselect(); + } else if (is_line_hidden(selection.from_line)) { + select(p_line, 9999, selection.to_line, selection.to_column); + } else if (is_line_hidden(selection.to_line)) { + select(selection.from_line, selection.from_column, p_line, 9999); + } + } + + // reset cursor + if (is_line_hidden(cursor.line)) { + cursor_set_line(p_line, false, false); + cursor_set_column(get_line(p_line).length(), false); + } + _update_scrollbars(); update(); } @@ -4461,6 +4556,8 @@ void TextEdit::unfold_line(int p_line) { ERR_FAIL_INDEX(p_line, text.size()); + if (!is_folded(p_line) && !is_line_hidden(p_line)) + return; int fold_start = p_line; for (fold_start = p_line; fold_start > 0; fold_start--) { if (is_folded(fold_start)) @@ -4475,7 +4572,7 @@ void TextEdit::unfold_line(int p_line) { break; } } - adjust_viewport_to_cursor(); + _update_scrollbars(); update(); } @@ -4705,13 +4802,14 @@ void TextEdit::set_v_scroll(int p_scroll) { p_scroll = 0; } if (!scroll_past_end_of_file_enabled) { - if (p_scroll + get_visible_rows() > get_line_count()) { + if (p_scroll + get_visible_rows() > get_total_unhidden_rows()) { int num_rows = num_lines_from(CLAMP(p_scroll, 0, text.size() - 1), MIN(get_visible_rows(), text.size() - 1 - p_scroll)); - p_scroll = get_line_count() - num_rows; + p_scroll = text.size() - num_rows; } } v_scroll->set_value(p_scroll); - cursor.line_ofs = p_scroll; + cursor.line_ofs = num_lines_from(0, p_scroll); + line_scroll_pos = p_scroll; } int TextEdit::get_h_scroll() const { @@ -5123,10 +5221,6 @@ int TextEdit::get_breakpoint_gutter_width() const { void TextEdit::set_draw_fold_gutter(bool p_draw) { draw_fold_gutter = p_draw; - if (draw_fold_gutter) - set_hiding_enabled(true); - else - unhide_all_lines(); update(); } @@ -5144,9 +5238,9 @@ int TextEdit::get_fold_gutter_width() const { } void TextEdit::set_hiding_enabled(int p_enabled) { + if (!p_enabled) + unhide_all_lines(); hiding_enabled = p_enabled; - if (!hiding_enabled) - set_draw_fold_gutter(false); update(); } @@ -5293,6 +5387,7 @@ void TextEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_hiding_enabled"), &TextEdit::is_hiding_enabled); ClassDB::bind_method(D_METHOD("set_line_as_hidden", "line", "enable"), &TextEdit::set_line_as_hidden); ClassDB::bind_method(D_METHOD("is_line_hidden"), &TextEdit::is_line_hidden); + ClassDB::bind_method(D_METHOD("fold_all_lines"), &TextEdit::fold_all_lines); ClassDB::bind_method(D_METHOD("unhide_all_lines"), &TextEdit::unhide_all_lines); ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line); ClassDB::bind_method(D_METHOD("unfold_line", "line"), &TextEdit::unfold_line); diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index c60ff1d09a..b1c7b14e58 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -75,6 +75,7 @@ class TextEdit : public Control { Ref<Texture> tab_icon; Ref<Texture> can_fold_icon; Ref<Texture> folded_icon; + Ref<Texture> folded_eol_icon; Ref<StyleBox> style_normal; Ref<StyleBox> style_focus; Ref<Font> font; @@ -302,9 +303,14 @@ class TextEdit : public Control { int search_result_line; int search_result_col; + double line_scroll_pos; + bool context_menu_enabled; int get_visible_rows() const; + int get_total_unhidden_rows() const; + double get_line_scroll_pos(bool p_recalculate = false) const; + void update_line_scroll_pos(); int get_char_count(); @@ -312,6 +318,7 @@ class TextEdit : public Control { int get_column_x_offset(int p_char, String p_str); void adjust_viewport_to_cursor(); + double get_scroll_line_diff() const; void _scroll_moved(double); void _update_scrollbars(); void _v_scroll_input(); @@ -334,8 +341,6 @@ class TextEdit : public Control { int get_row_height() const; - // int _get_fold_offset(int p_line_from, int p_line_to) const; - void _reset_caret_blink_timer(); void _toggle_draw_caret(); @@ -416,8 +421,10 @@ public: void set_line_as_breakpoint(int p_line, bool p_breakpoint); bool is_line_set_as_breakpoint(int p_line) const; void get_breakpoints(List<int> *p_breakpoints) const; + void set_line_as_hidden(int p_line, bool p_hidden); bool is_line_hidden(int p_line) const; + void fold_all_lines(); void unhide_all_lines(); int num_lines_from(int p_line_from, int unhidden_amount) const; int get_whitespace_level(int p_line) const; |