Browse Source

Added smooth scrolling to TextEdit

Paulb23 8 years ago
parent
commit
a142c9a2f0

+ 1 - 0
editor/code_editor.cpp

@@ -1087,6 +1087,7 @@ void CodeTextEditor::update_editor_settings() {
 	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->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"));
 }
 
 void CodeTextEditor::set_error(const String &p_error) {

+ 1 - 0
editor/editor_settings.cpp

@@ -615,6 +615,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
 	set("text_editor/line_numbers/line_length_guideline_column", 80);
 	hints["text_editor/line_numbers/line_length_guideline_column"] = PropertyInfo(Variant::INT, "text_editor/line_numbers/line_length_guideline_column", PROPERTY_HINT_RANGE, "20, 160, 10");
 
+	set("text_editor/open_scripts/smooth_scrolling", true);
 	set("text_editor/open_scripts/show_members_overview", true);
 
 	set("text_editor/files/trim_trailing_whitespace_on_save", false);

+ 51 - 3
scene/gui/scroll_bar.cpp

@@ -98,7 +98,18 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
 
 			if (ofs < grabber_ofs) {
 
-				set_value(get_value() - get_page());
+				if (scrolling) {
+					target_scroll = target_scroll - get_page();
+				} else {
+					target_scroll = get_value() - get_page();
+				}
+
+				if (smooth_scroll_enabled) {
+					scrolling = true;
+					set_fixed_process(true);
+				} else {
+					set_value(target_scroll);
+				}
 				return;
 			}
 
@@ -111,8 +122,18 @@ void ScrollBar::_gui_input(Ref<InputEvent> p_event) {
 				drag.value_at_click = get_as_ratio();
 				update();
 			} else {
+				if (scrolling) {
+					target_scroll = target_scroll + get_page();
+				} else {
+					target_scroll = get_value() + get_page();
+				}
 
-				set_value(get_value() + get_page());
+				if (smooth_scroll_enabled) {
+					scrolling = true;
+					set_fixed_process(true);
+				} else {
+					set_value(target_scroll);
+				}
 			}
 
 		} else {
@@ -311,7 +332,22 @@ void ScrollBar::_notification(int p_what) {
 
 	if (p_what == NOTIFICATION_FIXED_PROCESS) {
 
-		if (drag_slave_touching) {
+		if (scrolling) {
+			if (get_value() != target_scroll) {
+				double target = target_scroll - get_value();
+				double dist = sqrt(target * target);
+				double vel = ((target / dist) * 500) * get_fixed_process_delta_time();
+
+				if (vel >= dist) {
+					set_value(target_scroll);
+				} else {
+					set_value(get_value() + vel);
+				}
+			} else {
+				scrolling = false;
+				set_fixed_process(false);
+			}
+		} else if (drag_slave_touching) {
 
 			if (drag_slave_touching_deaccel) {
 
@@ -639,6 +675,14 @@ NodePath ScrollBar::get_drag_slave() const {
 	return drag_slave_path;
 }
 
+void ScrollBar::set_smooth_scroll_enabled(bool p_enable) {
+	smooth_scroll_enabled = p_enable;
+}
+
+bool ScrollBar::is_smooth_scroll_enabled() const {
+	return smooth_scroll_enabled;
+}
+
 #if 0
 
 void ScrollBar::mouse_button(const Point2& p_pos, int b->get_button_index(),bool b->is_pressed(),int p_modifier_mask) {
@@ -795,6 +839,10 @@ ScrollBar::ScrollBar(Orientation p_orientation) {
 	drag_slave_touching = false;
 	drag_slave_touching_deaccel = false;
 
+	scrolling = false;
+	target_scroll = 0;
+	smooth_scroll_enabled = false;
+
 	if (focus_by_default)
 		set_focus_mode(FOCUS_ALL);
 	set_step(0);

+ 7 - 0
scene/gui/scroll_bar.h

@@ -83,6 +83,10 @@ class ScrollBar : public Range {
 	bool drag_slave_touching_deaccel;
 	bool click_handled;
 
+	bool scrolling;
+	double target_scroll;
+	bool smooth_scroll_enabled;
+
 	void _drag_slave_exit();
 	void _drag_slave_input(const Ref<InputEvent> &p_input);
 
@@ -100,6 +104,9 @@ public:
 	void set_drag_slave(const NodePath &p_path);
 	NodePath get_drag_slave() const;
 
+	void set_smooth_scroll_enabled(bool p_enable);
+	bool is_smooth_scroll_enabled() const;
+
 	virtual Size2 get_minimum_size() const;
 	ScrollBar(Orientation p_orientation = VERTICAL);
 	~ScrollBar();

+ 82 - 5
scene/gui/text_edit.cpp

@@ -338,6 +338,11 @@ void TextEdit::_update_scrollbars() {
 		v_scroll->show();
 		v_scroll->set_max(total_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);
@@ -420,6 +425,24 @@ void TextEdit::_notification(int p_what) {
 			draw_caret = false;
 			update();
 		} break;
+		case NOTIFICATION_FIXED_PROCESS: {
+			if (scrolling && v_scroll->get_value() != target_v_scroll) {
+				double target_y = target_v_scroll - v_scroll->get_value();
+				double dist = sqrt(target_y * target_y);
+				double vel = ((target_y / dist) * 50) * get_fixed_process_delta_time();
+
+				if (vel >= dist) {
+					v_scroll->set_value(target_v_scroll);
+					scrolling = false;
+					set_fixed_process(false);
+				} else {
+					v_scroll->set_value(v_scroll->get_value() + vel);
+				}
+			} else {
+				scrolling = false;
+				set_fixed_process(false);
+			}
+		} break;
 		case NOTIFICATION_DRAW: {
 
 			if ((!has_focus() && !menu->has_focus()) || !window_has_focus) {
@@ -454,6 +477,7 @@ void TextEdit::_notification(int p_what) {
 			_update_scrollbars();
 
 			RID ci = get_canvas_item();
+			VisualServer::get_singleton()->canvas_item_set_clip(get_canvas_item(), true);
 			int xmargin_beg = cache.style_normal->get_margin(MARGIN_LEFT) + cache.line_number_w + cache.breakpoint_gutter_width;
 			int xmargin_end = cache.size.width - cache.style_normal->get_margin(MARGIN_RIGHT);
 			//let's do it easy for now:
@@ -674,7 +698,11 @@ void TextEdit::_notification(int p_what) {
 
 				int char_margin = xmargin_beg - cursor.x_ofs;
 				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) {
+					ofs_y -= (v_scroll->get_value() - cursor.line_ofs) * get_row_height();
+				}
+
 				bool prev_is_char = false;
 				bool prev_is_number = false;
 				bool in_keyword = false;
@@ -1500,7 +1528,7 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
 	float rows = p_mouse.y;
 	rows -= cache.style_normal->get_margin(MARGIN_TOP);
 	rows /= get_row_height();
-	int row = cursor.line_ofs + rows;
+	int row = cursor.line_ofs + (rows + (v_scroll->get_value() - cursor.line_ofs));
 
 	if (row < 0)
 		row = 0;
@@ -1566,10 +1594,43 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
 		if (mb->is_pressed()) {
 
 			if (mb->get_button_index() == BUTTON_WHEEL_UP && !mb->get_command()) {
-				v_scroll->set_value(v_scroll->get_value() - (3 * mb->get_factor()));
+				if (scrolling) {
+					target_v_scroll = (target_v_scroll - (3 * mb->get_factor()));
+				} else {
+					target_v_scroll = (v_scroll->get_value() - (3 * mb->get_factor()));
+				}
+
+				if (smooth_scroll_enabled) {
+					if (target_v_scroll <= 0) {
+						target_v_scroll = 0;
+					}
+					scrolling = true;
+					set_fixed_process(true);
+				} else {
+					v_scroll->set_value(target_v_scroll);
+				}
 			}
 			if (mb->get_button_index() == BUTTON_WHEEL_DOWN && !mb->get_command()) {
-				v_scroll->set_value(v_scroll->get_value() + (3 * mb->get_factor()));
+				if (scrolling) {
+					target_v_scroll = (target_v_scroll + (3 * mb->get_factor()));
+				} else {
+					target_v_scroll = (v_scroll->get_value() + (3 * mb->get_factor()));
+				}
+
+				if (smooth_scroll_enabled) {
+					int max_v_scroll = get_line_count() - 1;
+					if (!scroll_past_end_of_file_enabled) {
+						max_v_scroll -= get_visible_rows() - 1;
+					}
+
+					if (target_v_scroll > max_v_scroll) {
+						target_v_scroll = max_v_scroll;
+					}
+					scrolling = true;
+					set_fixed_process(true);
+				} else {
+					v_scroll->set_value(target_v_scroll);
+				}
 			}
 			if (mb->get_button_index() == BUTTON_WHEEL_LEFT) {
 				h_scroll->set_value(h_scroll->get_value() - (100 * mb->get_factor()));
@@ -3092,7 +3153,7 @@ int TextEdit::get_visible_rows() const {
 	int total = cache.size.height;
 	total -= cache.style_normal->get_minimum_size().height;
 	total /= get_row_height();
-	return total;
+	return total + 1;
 }
 void TextEdit::adjust_viewport_to_cursor() {
 
@@ -4194,6 +4255,15 @@ void TextEdit::set_h_scroll(int p_scroll) {
 	h_scroll->set_value(p_scroll);
 }
 
+void TextEdit::set_smooth_scroll_enabled(bool p_enable) {
+	v_scroll->set_smooth_scroll_enabled(p_enable);
+	smooth_scroll_enabled = p_enable;
+}
+
+bool TextEdit::is_smooth_scroll_enabled() const {
+	return smooth_scroll_enabled;
+}
+
 void TextEdit::set_completion(bool p_enabled, const Vector<String> &p_prefixes) {
 
 	completion_prefixes.clear();
@@ -4694,6 +4764,9 @@ void TextEdit::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("set_syntax_coloring", "enable"), &TextEdit::set_syntax_coloring);
 	ClassDB::bind_method(D_METHOD("is_syntax_coloring_enabled"), &TextEdit::is_syntax_coloring_enabled);
 
+	ClassDB::bind_method(D_METHOD("set_smooth_scroll_enable", "enable"), &TextEdit::set_smooth_scroll_enabled);
+	ClassDB::bind_method(D_METHOD("is_smooth_scroll_enabled"), &TextEdit::is_smooth_scroll_enabled);
+
 	ClassDB::bind_method(D_METHOD("add_keyword_color", "keyword", "color"), &TextEdit::add_keyword_color);
 	ClassDB::bind_method(D_METHOD("add_color_region", "begin_key", "end_key", "color", "line_only"), &TextEdit::add_color_region, DEFVAL(false));
 	ClassDB::bind_method(D_METHOD("clear_colors"), &TextEdit::clear_colors);
@@ -4703,6 +4776,7 @@ void TextEdit::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "syntax_highlighting"), "set_syntax_coloring", "is_syntax_coloring_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_line_numbers"), "set_show_line_numbers", "is_show_line_numbers_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "highlight_all_occurrences"), "set_highlight_all_occurrences", "is_highlight_all_occurrences_enabled");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "smooth_scrolling"), "set_smooth_scroll_enable", "is_smooth_scroll_enabled");
 
 	ADD_GROUP("Caret", "caret_");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_block_mode"), "cursor_set_block_mode", "cursor_is_block_mode");
@@ -4839,6 +4913,9 @@ TextEdit::TextEdit() {
 	insert_mode = false;
 	window_has_focus = true;
 	select_identifiers_enabled = false;
+	smooth_scroll_enabled = false;
+	scrolling = false;
+	target_v_scroll = 0;
 
 	raised_from_completion = false;
 

+ 7 - 0
scene/gui/text_edit.h

@@ -256,6 +256,10 @@ class TextEdit : public Control {
 	bool insert_mode;
 	bool select_identifiers_enabled;
 
+	bool smooth_scroll_enabled;
+	bool scrolling;
+	float target_v_scroll;
+
 	bool raised_from_completion;
 
 	String highlighted_word;
@@ -487,6 +491,9 @@ public:
 	int get_h_scroll() const;
 	void set_h_scroll(int p_scroll);
 
+	void set_smooth_scroll_enabled(bool p_enable);
+	bool is_smooth_scroll_enabled() const;
+
 	uint32_t get_version() const;
 	uint32_t get_saved_version() const;
 	void tag_saved_version();