diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 51b22df331a..c33340ce69f 100644 --- a/editor/code_editor.cpp +++ b/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) { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 70367f1e077..8494c7199e2 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -615,6 +615,7 @@ void EditorSettings::_load_defaults(Ref 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); diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp index 2ccdbb05a92..6519cde6d3c 100644 --- a/scene/gui/scroll_bar.cpp +++ b/scene/gui/scroll_bar.cpp @@ -98,7 +98,18 @@ void ScrollBar::_gui_input(Ref 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 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); diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h index 8310e12590e..e22d4da46d8 100644 --- a/scene/gui/scroll_bar.h +++ b/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 &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(); diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 2b111c50a6e..650fdfbc5fd 100644 --- a/scene/gui/text_edit.cpp +++ b/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 &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 &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; diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index 4c17347a5df..c4e07005311 100644 --- a/scene/gui/text_edit.h +++ b/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();