浏览代码

scrolling fixes

Ian 8 年之前
父节点
当前提交
1e59169d2d
共有 5 个文件被更改,包括 310 次插入194 次删除
  1. 1 0
      editor/code_editor.cpp
  2. 86 74
      editor/plugins/script_text_editor.cpp
  3. 2 1
      editor/plugins/script_text_editor.h
  4. 212 117
      scene/gui/text_edit.cpp
  5. 9 2
      scene/gui/text_edit.h

+ 1 - 0
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_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->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_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->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->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"));
 	text_editor->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/open_scripts/smooth_scrolling"));

+ 86 - 74
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) {
 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() {
 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) {
 void ScriptTextEditor::_edit_option(int p_op) {
 
 
+	TextEdit *tx = code_editor->get_text_edit();
+
 	switch (p_op) {
 	switch (p_op) {
 		case EDIT_UNDO: {
 		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;
 		} break;
 		case EDIT_REDO: {
 		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;
 		} break;
 		case EDIT_CUT: {
 		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;
 		} break;
 		case EDIT_COPY: {
 		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;
 		} break;
 		case EDIT_PASTE: {
 		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;
 		} break;
 		case EDIT_SELECT_ALL: {
 		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;
 		} break;
 		case EDIT_MOVE_LINE_UP: {
 		case EDIT_MOVE_LINE_UP: {
 
 
-			TextEdit *tx = code_editor->get_text_edit();
 			Ref<Script> scr = script;
 			Ref<Script> scr = script;
 			if (scr.is_null())
 			if (scr.is_null())
 				return;
 				return;
@@ -841,8 +845,8 @@ void ScriptTextEditor::_edit_option(int p_op) {
 					if (line_id == 0 || next_id < 0)
 					if (line_id == 0 || next_id < 0)
 						return;
 						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->swap_lines(line_id, next_id);
 					tx->cursor_set_line(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)
 				if (line_id == 0 || next_id < 0)
 					return;
 					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->swap_lines(line_id, next_id);
 				tx->cursor_set_line(next_id);
 				tx->cursor_set_line(next_id);
 			}
 			}
 			tx->end_complex_operation();
 			tx->end_complex_operation();
 			tx->update();
 			tx->update();
-
 		} break;
 		} break;
 		case EDIT_MOVE_LINE_DOWN: {
 		case EDIT_MOVE_LINE_DOWN: {
 
 
-			TextEdit *tx = code_editor->get_text_edit();
 			Ref<Script> scr = get_edited_script();
 			Ref<Script> scr = get_edited_script();
 			if (scr.is_null())
 			if (scr.is_null())
 				return;
 				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())
 					if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count())
 						return;
 						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->swap_lines(line_id, next_id);
 					tx->cursor_set_line(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())
 				if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count())
 					return;
 					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->swap_lines(line_id, next_id);
 				tx->cursor_set_line(next_id);
 				tx->cursor_set_line(next_id);
@@ -916,7 +918,6 @@ void ScriptTextEditor::_edit_option(int p_op) {
 		} break;
 		} break;
 		case EDIT_INDENT_LEFT: {
 		case EDIT_INDENT_LEFT: {
 
 
-			TextEdit *tx = code_editor->get_text_edit();
 			Ref<Script> scr = get_edited_script();
 			Ref<Script> scr = get_edited_script();
 			if (scr.is_null())
 			if (scr.is_null())
 				return;
 				return;
@@ -941,11 +942,9 @@ void ScriptTextEditor::_edit_option(int p_op) {
 			tx->end_complex_operation();
 			tx->end_complex_operation();
 			tx->update();
 			tx->update();
 			//tx->deselect();
 			//tx->deselect();
-
 		} break;
 		} break;
 		case EDIT_INDENT_RIGHT: {
 		case EDIT_INDENT_RIGHT: {
 
 
-			TextEdit *tx = code_editor->get_text_edit();
 			Ref<Script> scr = get_edited_script();
 			Ref<Script> scr = get_edited_script();
 			if (scr.is_null())
 			if (scr.is_null())
 				return;
 				return;
@@ -962,11 +961,9 @@ void ScriptTextEditor::_edit_option(int p_op) {
 			tx->end_complex_operation();
 			tx->end_complex_operation();
 			tx->update();
 			tx->update();
 			//tx->deselect();
 			//tx->deselect();
-
 		} break;
 		} break;
 		case EDIT_DELETE_LINE: {
 		case EDIT_DELETE_LINE: {
 
 
-			TextEdit *tx = code_editor->get_text_edit();
 			Ref<Script> scr = get_edited_script();
 			Ref<Script> scr = get_edited_script();
 			if (scr.is_null())
 			if (scr.is_null())
 				return;
 				return;
@@ -975,13 +972,12 @@ void ScriptTextEditor::_edit_option(int p_op) {
 			int line = tx->cursor_get_line();
 			int line = tx->cursor_get_line();
 			tx->set_line(tx->cursor_get_line(), "");
 			tx->set_line(tx->cursor_get_line(), "");
 			tx->backspace_at_cursor();
 			tx->backspace_at_cursor();
+			tx->unfold_line(line);
 			tx->cursor_set_line(line);
 			tx->cursor_set_line(line);
 			tx->end_complex_operation();
 			tx->end_complex_operation();
-
 		} break;
 		} break;
 		case EDIT_CLONE_DOWN: {
 		case EDIT_CLONE_DOWN: {
 
 
-			TextEdit *tx = code_editor->get_text_edit();
 			Ref<Script> scr = get_edited_script();
 			Ref<Script> scr = get_edited_script();
 			if (scr.is_null())
 			if (scr.is_null())
 				return;
 				return;
@@ -1000,6 +996,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
 			tx->begin_complex_operation();
 			tx->begin_complex_operation();
 			for (int i = from_line; i <= to_line; i++) {
 			for (int i = from_line; i <= to_line; i++) {
 
 
+				tx->unfold_line(i);
 				if (i >= tx->get_line_count() - 1) {
 				if (i >= tx->get_line_count() - 1) {
 					tx->set_line(i, tx->get_line(i) + "\n");
 					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->end_complex_operation();
 			tx->update();
 			tx->update();
-
 		} break;
 		} break;
 		case EDIT_FOLD_LINE: {
 		case EDIT_FOLD_LINE: {
 
 
-			TextEdit *tx = code_editor->get_text_edit();
 			tx->fold_line(tx->cursor_get_line());
 			tx->fold_line(tx->cursor_get_line());
 			tx->update();
 			tx->update();
 		} break;
 		} break;
 		case EDIT_UNFOLD_LINE: {
 		case EDIT_UNFOLD_LINE: {
 
 
-			TextEdit *tx = code_editor->get_text_edit();
 			tx->unfold_line(tx->cursor_get_line());
 			tx->unfold_line(tx->cursor_get_line());
 			tx->update();
 			tx->update();
 		} break;
 		} break;
+		case EDIT_FOLD_ALL_LINES: {
+
+			tx->fold_all_lines();
+			tx->update();
+		} break;
 		case EDIT_UNFOLD_ALL_LINES: {
 		case EDIT_UNFOLD_ALL_LINES: {
 
 
-			TextEdit *tx = code_editor->get_text_edit();
 			tx->unhide_all_lines();
 			tx->unhide_all_lines();
 			tx->update();
 			tx->update();
 		} break;
 		} break;
 		case EDIT_TOGGLE_COMMENT: {
 		case EDIT_TOGGLE_COMMENT: {
 
 
-			TextEdit *tx = code_editor->get_text_edit();
 			Ref<Script> scr = get_edited_script();
 			Ref<Script> scr = get_edited_script();
 			if (scr.is_null())
 			if (scr.is_null())
 				return;
 				return;
@@ -1086,62 +1083,65 @@ void ScriptTextEditor::_edit_option(int p_op) {
 			tx->end_complex_operation();
 			tx->end_complex_operation();
 			tx->update();
 			tx->update();
 			//tx->deselect();
 			//tx->deselect();
-
 		} break;
 		} break;
 		case EDIT_COMPLETE: {
 		case EDIT_COMPLETE: {
 
 
-			code_editor->get_text_edit()->query_code_comple();
-
+			tx->query_code_comple();
 		} break;
 		} break;
 		case EDIT_AUTO_INDENT: {
 		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();
 			Ref<Script> scr = get_edited_script();
 			if (scr.is_null())
 			if (scr.is_null())
 				return;
 				return;
 
 
-			te->begin_complex_operation();
+			tx->begin_complex_operation();
 			int begin, end;
 			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
 				// 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--;
 					end--;
 				}
 				}
 			} else {
 			} else {
 				begin = 0;
 				begin = 0;
-				end = te->get_line_count() - 1;
+				end = tx->get_line_count() - 1;
 			}
 			}
 			scr->get_language()->auto_indent_code(text, begin, end);
 			scr->get_language()->auto_indent_code(text, begin, end);
 			Vector<String> lines = text.split("\n");
 			Vector<String> lines = text.split("\n");
 			for (int i = begin; i <= end; ++i) {
 			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;
 		} break;
 		case EDIT_TRIM_TRAILING_WHITESAPCE: {
 		case EDIT_TRIM_TRAILING_WHITESAPCE: {
+
 			trim_trailing_whitespace();
 			trim_trailing_whitespace();
 		} break;
 		} break;
 		case EDIT_CONVERT_INDENT_TO_SPACES: {
 		case EDIT_CONVERT_INDENT_TO_SPACES: {
+
 			convert_indent_to_spaces();
 			convert_indent_to_spaces();
 		} break;
 		} break;
 		case EDIT_CONVERT_INDENT_TO_TABS: {
 		case EDIT_CONVERT_INDENT_TO_TABS: {
+
 			convert_indent_to_tabs();
 			convert_indent_to_tabs();
 		} break;
 		} break;
 		case EDIT_PICK_COLOR: {
 		case EDIT_PICK_COLOR: {
+
 			color_panel->popup();
 			color_panel->popup();
 		} break;
 		} break;
 		case EDIT_TO_UPPERCASE: {
 		case EDIT_TO_UPPERCASE: {
+
 			_convert_case(UPPER);
 			_convert_case(UPPER);
 		} break;
 		} break;
 		case EDIT_TO_LOWERCASE: {
 		case EDIT_TO_LOWERCASE: {
+
 			_convert_case(LOWER);
 			_convert_case(LOWER);
 		} break;
 		} break;
 		case EDIT_CAPITALIZE: {
 		case EDIT_CAPITALIZE: {
+
 			_convert_case(CAPITALIZE);
 			_convert_case(CAPITALIZE);
 		} break;
 		} break;
 		case SEARCH_FIND: {
 		case SEARCH_FIND: {
@@ -1166,41 +1166,47 @@ void ScriptTextEditor::_edit_option(int p_op) {
 		} break;
 		} break;
 		case SEARCH_GOTO_LINE: {
 		case SEARCH_GOTO_LINE: {
 
 
-			goto_line_dialog->popup_find_line(code_editor->get_text_edit());
+			goto_line_dialog->popup_find_line(tx);
 		} break;
 		} break;
 		case DEBUG_TOGGLE_BREAKPOINT: {
 		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);
 			ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak);
 		} break;
 		} break;
 		case DEBUG_REMOVE_ALL_BREAKPOINTS: {
 		case DEBUG_REMOVE_ALL_BREAKPOINTS: {
+
 			List<int> bpoints;
 			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()) {
 			for (List<int>::Element *E = bpoints.front(); E; E = E->next()) {
 				int line = E->get();
 				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);
 				ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak);
 			}
 			}
 		}
 		}
 		case DEBUG_GOTO_NEXT_BREAKPOINT: {
 		case DEBUG_GOTO_NEXT_BREAKPOINT: {
+
 			List<int> bpoints;
 			List<int> bpoints;
-			code_editor->get_text_edit()->get_breakpoints(&bpoints);
+			tx->get_breakpoints(&bpoints);
 			if (bpoints.size() <= 0) {
 			if (bpoints.size() <= 0) {
 				return;
 				return;
 			}
 			}
 
 
-			int line = code_editor->get_text_edit()->cursor_get_line();
+			int line = tx->cursor_get_line();
+
 			// wrap around
 			// wrap around
 			if (line >= bpoints[bpoints.size() - 1]) {
 			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 {
 			} else {
 				for (List<int>::Element *E = bpoints.front(); E; E = E->next()) {
 				for (List<int>::Element *E = bpoints.front(); E; E = E->next()) {
 					int bline = E->get();
 					int bline = E->get();
 					if (bline > line) {
 					if (bline > line) {
-						code_editor->get_text_edit()->cursor_set_line(bline);
+						tx->unfold_line(bline);
+						tx->cursor_set_line(bline);
 						return;
 						return;
 					}
 					}
 				}
 				}
@@ -1208,21 +1214,24 @@ void ScriptTextEditor::_edit_option(int p_op) {
 
 
 		} break;
 		} break;
 		case DEBUG_GOTO_PREV_BREAKPOINT: {
 		case DEBUG_GOTO_PREV_BREAKPOINT: {
+
 			List<int> bpoints;
 			List<int> bpoints;
-			code_editor->get_text_edit()->get_breakpoints(&bpoints);
+			tx->get_breakpoints(&bpoints);
 			if (bpoints.size() <= 0) {
 			if (bpoints.size() <= 0) {
 				return;
 				return;
 			}
 			}
 
 
-			int line = code_editor->get_text_edit()->cursor_get_line();
+			int line = tx->cursor_get_line();
 			// wrap around
 			// wrap around
 			if (line <= bpoints[0]) {
 			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 {
 			} else {
 				for (List<int>::Element *E = bpoints.back(); E; E = E->prev()) {
 				for (List<int>::Element *E = bpoints.back(); E; E = E->prev()) {
 					int bline = E->get();
 					int bline = E->get();
 					if (bline < line) {
 					if (bline < line) {
-						code_editor->get_text_edit()->cursor_set_line(bline);
+						tx->unfold_line(bline);
+						tx->cursor_set_line(bline);
 						return;
 						return;
 					}
 					}
 				}
 				}
@@ -1231,9 +1240,10 @@ void ScriptTextEditor::_edit_option(int p_op) {
 		} break;
 		} break;
 
 
 		case HELP_CONTEXTUAL: {
 		case HELP_CONTEXTUAL: {
-			String text = code_editor->get_text_edit()->get_selection_text();
+
+			String text = tx->get_selection_text();
 			if (text == "")
 			if (text == "")
-				text = code_editor->get_text_edit()->get_word_under_cursor();
+				text = tx->get_word_under_cursor();
 			if (text != "") {
 			if (text != "") {
 				emit_signal("request_help_search", 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_selection = (tx->get_selection_text().length() > 0);
 			bool have_color = (tx->get_word_at_pos(mpos) == "Color");
 			bool have_color = (tx->get_word_at_pos(mpos) == "Color");
 			int fold_state = 0;
 			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) {
 			if (have_color) {
 
 
 				String line = tx->get_line(row);
 				String line = tx->get_line(row);
@@ -1452,7 +1462,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) {
 					have_color = false;
 					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);
 	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();
 	context_menu->clear();
 	if (p_selection) {
 	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/indent_right"), EDIT_INDENT_RIGHT);
 		context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_comment"), EDIT_TOGGLE_COMMENT);
 		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
 		// can fold
 		context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_line"), EDIT_FOLD_LINE);
 		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
 		// can unfold
 		context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_line"), EDIT_UNFOLD_LINE);
 		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/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/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_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_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_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
 	edit_menu->get_popup()->add_separator();
 	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/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/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/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);
 	ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), 0);
 #ifdef OSX_ENABLED
 #ifdef OSX_ENABLED
 	ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CTRL | KEY_SPACE);
 	ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CTRL | KEY_SPACE);

+ 2 - 1
editor/plugins/script_text_editor.h

@@ -93,6 +93,7 @@ class ScriptTextEditor : public ScriptEditorBase {
 		EDIT_CAPITALIZE,
 		EDIT_CAPITALIZE,
 		EDIT_FOLD_LINE,
 		EDIT_FOLD_LINE,
 		EDIT_UNFOLD_LINE,
 		EDIT_UNFOLD_LINE,
+		EDIT_FOLD_ALL_LINES,
 		EDIT_UNFOLD_ALL_LINES,
 		EDIT_UNFOLD_ALL_LINES,
 		SEARCH_FIND,
 		SEARCH_FIND,
 		SEARCH_FIND_NEXT,
 		SEARCH_FIND_NEXT,
@@ -121,7 +122,7 @@ protected:
 	static void _bind_methods();
 	static void _bind_methods();
 
 
 	void _edit_option(int p_op);
 	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 _text_edit_gui_input(const Ref<InputEvent> &ev);
 	void _color_changed(const Color &p_color);
 	void _color_changed(const Color &p_color);
 
 

+ 212 - 117
scene/gui/text_edit.cpp

@@ -300,9 +300,9 @@ void TextEdit::_update_scrollbars() {
 	int visible_rows = get_visible_rows();
 	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 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) {
 	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;
 	int vscroll_pixels = v_scroll->get_combined_minimum_size().width;
@@ -347,19 +347,18 @@ void TextEdit::_update_scrollbars() {
 
 
 		v_scroll->show();
 		v_scroll->show();
 		v_scroll->set_max(total_rows);
 		v_scroll->set_max(total_rows);
-		v_scroll->set_page(num_rows);
+		v_scroll->set_page(visible_rows);
 		if (smooth_scroll_enabled) {
 		if (smooth_scroll_enabled) {
 			v_scroll->set_step(0.25);
 			v_scroll->set_step(0.25);
 		} else {
 		} else {
 			v_scroll->set_step(1);
 			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 {
 	} else {
 		cursor.line_ofs = 0;
 		cursor.line_ofs = 0;
+		line_scroll_pos = 0;
+		v_scroll->set_value(0);
 		v_scroll->hide();
 		v_scroll->hide();
 	}
 	}
 
 
@@ -794,6 +793,7 @@ void TextEdit::_notification(int p_what) {
 			String highlighted_text = get_selection_text();
 			String highlighted_text = get_selection_text();
 
 
 			String line_num_padding = line_numbers_zero_padded ? "0" : " ";
 			String line_num_padding = line_numbers_zero_padded ? "0" : " ";
+			update_line_scroll_pos();
 
 
 			int line = cursor.line_ofs - 1;
 			int line = cursor.line_ofs - 1;
 			for (int i = 0; i < visible_rows; i++) {
 			for (int i = 0; i < visible_rows; i++) {
@@ -819,7 +819,7 @@ void TextEdit::_notification(int p_what) {
 				int char_ofs = 0;
 				int char_ofs = 0;
 				int ofs_y = (i * get_row_height() + cache.line_spacing / 2);
 				int ofs_y = (i * get_row_height() + cache.line_spacing / 2);
 				if (smooth_scroll_enabled) {
 				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;
 				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) {
 				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;
 					int gutter_left = cache.style_normal->get_margin(MARGIN_LEFT) + cache.breakpoint_gutter_width + cache.line_number_w;
 					if (is_folded(line)) {
 					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;
 						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)) {
 					} 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;
 						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;
 					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) {
 				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;
 	float rows = p_mouse.y;
 	rows -= cache.style_normal->get_margin(MARGIN_TOP);
 	rows -= cache.style_normal->get_margin(MARGIN_TOP);
 	rows /= get_row_height();
 	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()) {
 	if (is_hiding_enabled()) {
 		// row will be offset by the hidden rows
 		// 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)
 	if (row < 0)
 		row = 0; //todo
 		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);
 					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 (smooth_scroll_enabled) {
 					if (target_v_scroll <= 0) {
 					if (target_v_scroll <= 0) {
 						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);
 					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) {
 				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) {
 					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) {
 					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();
 				_reset_caret_blink_timer();
 
 
 				int row, col;
 				int row, col;
+				update_line_scroll_pos();
 				_get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col);
 				_get_mouse_pos(Point2i(mb->get_position().x, mb->get_position().y), row, col);
 
 
 				if (mb->get_command() && highlighted_word != String()) {
 				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 left_margin = cache.style_normal->get_margin(MARGIN_LEFT);
 					int gutter_left = left_margin + cache.breakpoint_gutter_width + cache.line_number_w;
 					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)) {
 						if (is_folded(row)) {
 							unfold_line(row);
 							unfold_line(row);
 						} else if (can_fold(row)) {
 						} else if (can_fold(row)) {
 							fold_line(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;
 						return;
 					}
 					}
 				}
 				}
@@ -2124,7 +2117,6 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
 
 
 						_confirm_completion();
 						_confirm_completion();
 						accept_event();
 						accept_event();
-						emit_signal("request_completion");
 						return;
 						return;
 					}
 					}
 
 
@@ -2537,9 +2529,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
 				} else if (cursor.column == 0) {
 				} else if (cursor.column == 0) {
 
 
 					if (cursor.line > 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());
 						cursor_set_column(text[cursor.line].length());
 					}
 					}
 				} else {
 				} else {
@@ -2602,10 +2592,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
 				} else if (cursor.column == text[cursor.line].length()) {
 				} else if (cursor.column == text[cursor.line].length()) {
 
 
 					if (cursor.line < text.size() - 1) {
 					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);
 						cursor_set_column(0);
 					}
 					}
 				} else {
 				} else {
@@ -2646,7 +2633,7 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
 					cursor_set_line(0);
 					cursor_set_line(0);
 				else
 				else
 #endif
 #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())
 				if (k->get_shift())
 					_post_shift_selection();
 					_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);
 					cursor_set_line(text.size() - 1, true, false);
 				else
 				else
 #endif
 #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())
 				if (k->get_shift())
 					_post_shift_selection();
 					_post_shift_selection();
@@ -3105,12 +3092,13 @@ void TextEdit::_scroll_lines_up() {
 
 
 	// adjust the vertical scroll
 	// adjust the vertical scroll
 	if (get_v_scroll() > 0) {
 	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
 	// 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;
 	scrolling = false;
 
 
 	// calculate the maximum vertical scroll position
 	// 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) {
 	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
 	// adjust the vertical scroll
 	if (get_v_scroll() < max_v_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
 	// 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;
 	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() {
 void TextEdit::adjust_viewport_to_cursor() {
 	scrolling = false;
 	scrolling = false;
 
 
-	if (cursor.line_ofs > cursor.line)
+	if (cursor.line_ofs > cursor.line) {
 		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;
 	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())
 	if (v_scroll->is_visible_in_tree())
@@ -3405,16 +3441,19 @@ void TextEdit::adjust_viewport_to_cursor() {
 	int visible_rows = get_visible_rows();
 	int visible_rows = get_visible_rows();
 	if (h_scroll->is_visible_in_tree())
 	if (h_scroll->is_visible_in_tree())
 		visible_rows -= ((h_scroll->get_combined_minimum_size().height - 1) / get_row_height());
 		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));
 	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;
 		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]);
 	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)
 	if (cursor_x < cursor.x_ofs)
 		cursor.x_ofs = cursor_x;
 		cursor.x_ofs = cursor_x;
 
 
+	update_line_scroll_pos();
+	v_scroll->set_value(get_line_scroll_pos() + 1);
 	update();
 	update();
 	/*
 	/*
 	get_range()->set_max(text.size());
 	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));
 	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);
 	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]);
 	int cursor_x = get_column_x_offset(cursor.column, text[cursor.line]);
 
 
 	if (cursor_x > (cursor.x_ofs + visible_width))
 	if (cursor_x > (cursor.x_ofs + visible_width))
@@ -3464,6 +3504,9 @@ void TextEdit::center_viewport_to_cursor() {
 	if (cursor_x < cursor.x_ofs)
 	if (cursor_x < cursor.x_ofs)
 		cursor.x_ofs = cursor_x;
 		cursor.x_ofs = cursor_x;
 
 
+	update_line_scroll_pos();
+	v_scroll->set_value(get_line_scroll_pos());
+
 	update();
 	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;
 		p_row = (int)text.size() - 1;
 
 
 	if (!p_can_be_hidden) {
 	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())
 	if (h_scroll->is_visible_in_tree())
 		cursor.x_ofs = h_scroll->get_value();
 		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();
 	update();
 }
 }
 
 
@@ -3685,9 +3721,42 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const {
 		return CURSOR_POINTING_HAND;
 		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;
 	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;
 		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;
 	return CURSOR_IBEAM;
 }
 }
 
 
@@ -3701,6 +3770,7 @@ void TextEdit::set_text(String p_text) {
 	cursor.line = 0;
 	cursor.line = 0;
 	cursor.x_ofs = 0;
 	cursor.x_ofs = 0;
 	cursor.line_ofs = 0;
 	cursor.line_ofs = 0;
+	line_scroll_pos = 0;
 	cursor.last_fit_x = 0;
 	cursor.last_fit_x = 0;
 	cursor_set_line(0);
 	cursor_set_line(0);
 	cursor_set_column(0);
 	cursor_set_column(0);
@@ -3786,6 +3856,7 @@ void TextEdit::_clear() {
 	cursor.line = 0;
 	cursor.line = 0;
 	cursor.x_ofs = 0;
 	cursor.x_ofs = 0;
 	cursor.line_ofs = 0;
 	cursor.line_ofs = 0;
+	line_scroll_pos = 0;
 	cursor.last_fit_x = 0;
 	cursor.last_fit_x = 0;
 }
 }
 
 
@@ -3864,8 +3935,9 @@ void TextEdit::_update_caches() {
 	cache.line_spacing = get_constant("line_spacing");
 	cache.line_spacing = get_constant("line_spacing");
 	cache.row_height = cache.font->get_height() + cache.line_spacing;
 	cache.row_height = cache.font->get_height() + cache.line_spacing;
 	cache.tab_icon = get_icon("tab");
 	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);
 	text.set_font(cache.font);
 }
 }
 
 
@@ -4326,11 +4398,21 @@ bool TextEdit::is_line_hidden(int p_line) const {
 	return text.is_hidden(p_line);
 	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() {
 void TextEdit::unhide_all_lines() {
 
 
 	for (int i = 0; i < text.size(); i++) {
 	for (int i = 0; i < text.size(); i++) {
 		text.set_hidden(i, false);
 		text.set_hidden(i, false);
 	}
 	}
+	_update_scrollbars();
 	update();
 	update();
 }
 }
 
 
@@ -4377,9 +4459,7 @@ int TextEdit::get_whitespace_level(int p_line) const {
 		} else if (text[p_line][i] == ' ') {
 		} else if (text[p_line][i] == ' ') {
 			whitespace_count++;
 			whitespace_count++;
 		} else if (text[p_line][i] == '#') {
 		} else if (text[p_line][i] == '#') {
-			if (whitespace_count != 0) {
-				break;
-			}
+			break;
 		} else {
 		} else {
 			break;
 			break;
 		}
 		}
@@ -4392,14 +4472,14 @@ bool TextEdit::can_fold(int p_line) const {
 	ERR_FAIL_INDEX_V(p_line, text.size(), false);
 	ERR_FAIL_INDEX_V(p_line, text.size(), false);
 	if (!is_hiding_enabled())
 	if (!is_hiding_enabled())
 		return false;
 		return false;
-	if (!draw_fold_gutter)
-		return false;
-	if (p_line + 2 >= text.size())
+	if (p_line + 1 >= text.size())
 		return false;
 		return false;
 	if (text[p_line].size() == 0)
 	if (text[p_line].size() == 0)
 		return false;
 		return false;
 	if (is_folded(p_line))
 	if (is_folded(p_line))
 		return false;
 		return false;
+	if (is_line_hidden(p_line))
+		return false;
 
 
 	int start_indent = get_whitespace_level(p_line);
 	int start_indent = get_whitespace_level(p_line);
 
 
@@ -4434,6 +4514,7 @@ void TextEdit::fold_line(int p_line) {
 	if (!can_fold(p_line))
 	if (!can_fold(p_line))
 		return;
 		return;
 
 
+	// hide lines below this one
 	int start_indent = get_whitespace_level(p_line);
 	int start_indent = get_whitespace_level(p_line);
 	for (int i = p_line + 1; i < text.size(); i++) {
 	for (int i = p_line + 1; i < text.size(); i++) {
 		int cur_indent = get_whitespace_level(i);
 		int cur_indent = get_whitespace_level(i);
@@ -4447,13 +4528,27 @@ void TextEdit::fold_line(int p_line) {
 				else
 				else
 					break;
 					break;
 			}
 			}
-			if (is_line_hidden(cursor.line)) {
-				cursor_set_line(i, true, false);
-			}
 			break;
 			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();
 	update();
 }
 }
 
 
@@ -4461,6 +4556,8 @@ void TextEdit::unfold_line(int p_line) {
 
 
 	ERR_FAIL_INDEX(p_line, text.size());
 	ERR_FAIL_INDEX(p_line, text.size());
 
 
+	if (!is_folded(p_line) && !is_line_hidden(p_line))
+		return;
 	int fold_start = p_line;
 	int fold_start = p_line;
 	for (fold_start = p_line; fold_start > 0; fold_start--) {
 	for (fold_start = p_line; fold_start > 0; fold_start--) {
 		if (is_folded(fold_start))
 		if (is_folded(fold_start))
@@ -4475,7 +4572,7 @@ void TextEdit::unfold_line(int p_line) {
 			break;
 			break;
 		}
 		}
 	}
 	}
-	adjust_viewport_to_cursor();
+	_update_scrollbars();
 	update();
 	update();
 }
 }
 
 
@@ -4705,13 +4802,14 @@ void TextEdit::set_v_scroll(int p_scroll) {
 		p_scroll = 0;
 		p_scroll = 0;
 	}
 	}
 	if (!scroll_past_end_of_file_enabled) {
 	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));
 			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);
 	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 {
 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) {
 void TextEdit::set_draw_fold_gutter(bool p_draw) {
 	draw_fold_gutter = p_draw;
 	draw_fold_gutter = p_draw;
-	if (draw_fold_gutter)
-		set_hiding_enabled(true);
-	else
-		unhide_all_lines();
 	update();
 	update();
 }
 }
 
 
@@ -5144,9 +5238,9 @@ int TextEdit::get_fold_gutter_width() const {
 }
 }
 
 
 void TextEdit::set_hiding_enabled(int p_enabled) {
 void TextEdit::set_hiding_enabled(int p_enabled) {
+	if (!p_enabled)
+		unhide_all_lines();
 	hiding_enabled = p_enabled;
 	hiding_enabled = p_enabled;
-	if (!hiding_enabled)
-		set_draw_fold_gutter(false);
 	update();
 	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("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("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("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("unhide_all_lines"), &TextEdit::unhide_all_lines);
 	ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line);
 	ClassDB::bind_method(D_METHOD("fold_line", "line"), &TextEdit::fold_line);
 	ClassDB::bind_method(D_METHOD("unfold_line", "line"), &TextEdit::unfold_line);
 	ClassDB::bind_method(D_METHOD("unfold_line", "line"), &TextEdit::unfold_line);

+ 9 - 2
scene/gui/text_edit.h

@@ -75,6 +75,7 @@ class TextEdit : public Control {
 		Ref<Texture> tab_icon;
 		Ref<Texture> tab_icon;
 		Ref<Texture> can_fold_icon;
 		Ref<Texture> can_fold_icon;
 		Ref<Texture> folded_icon;
 		Ref<Texture> folded_icon;
+		Ref<Texture> folded_eol_icon;
 		Ref<StyleBox> style_normal;
 		Ref<StyleBox> style_normal;
 		Ref<StyleBox> style_focus;
 		Ref<StyleBox> style_focus;
 		Ref<Font> font;
 		Ref<Font> font;
@@ -302,9 +303,14 @@ class TextEdit : public Control {
 	int search_result_line;
 	int search_result_line;
 	int search_result_col;
 	int search_result_col;
 
 
+	double line_scroll_pos;
+
 	bool context_menu_enabled;
 	bool context_menu_enabled;
 
 
 	int get_visible_rows() const;
 	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();
 	int get_char_count();
 
 
@@ -312,6 +318,7 @@ class TextEdit : public Control {
 	int get_column_x_offset(int p_char, String p_str);
 	int get_column_x_offset(int p_char, String p_str);
 
 
 	void adjust_viewport_to_cursor();
 	void adjust_viewport_to_cursor();
+	double get_scroll_line_diff() const;
 	void _scroll_moved(double);
 	void _scroll_moved(double);
 	void _update_scrollbars();
 	void _update_scrollbars();
 	void _v_scroll_input();
 	void _v_scroll_input();
@@ -334,8 +341,6 @@ class TextEdit : public Control {
 
 
 	int get_row_height() const;
 	int get_row_height() const;
 
 
-	// int _get_fold_offset(int p_line_from, int p_line_to) const;
-
 	void _reset_caret_blink_timer();
 	void _reset_caret_blink_timer();
 	void _toggle_draw_caret();
 	void _toggle_draw_caret();
 
 
@@ -416,8 +421,10 @@ public:
 	void set_line_as_breakpoint(int p_line, bool p_breakpoint);
 	void set_line_as_breakpoint(int p_line, bool p_breakpoint);
 	bool is_line_set_as_breakpoint(int p_line) const;
 	bool is_line_set_as_breakpoint(int p_line) const;
 	void get_breakpoints(List<int> *p_breakpoints) const;
 	void get_breakpoints(List<int> *p_breakpoints) const;
+
 	void set_line_as_hidden(int p_line, bool p_hidden);
 	void set_line_as_hidden(int p_line, bool p_hidden);
 	bool is_line_hidden(int p_line) const;
 	bool is_line_hidden(int p_line) const;
+	void fold_all_lines();
 	void unhide_all_lines();
 	void unhide_all_lines();
 	int num_lines_from(int p_line_from, int unhidden_amount) const;
 	int num_lines_from(int p_line_from, int unhidden_amount) const;
 	int get_whitespace_level(int p_line) const;
 	int get_whitespace_level(int p_line) const;