Add auto-scroll behavior when selecting text outside the visible area in RichTextLabel

This commit is contained in:
AndrewYuan34 2025-03-28 03:21:20 -04:00
parent 42c7f14422
commit 4774b57e4d
2 changed files with 132 additions and 80 deletions

View file

@ -2596,6 +2596,11 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
deselect(); deselect();
} }
} }
if (!selection.drag_attempt) {
is_selecting_text = true;
click_select_held->start();
}
} }
} }
} else if (b->is_pressed() && b->is_double_click() && selection.enabled) { } else if (b->is_pressed() && b->is_double_click() && selection.enabled) {
@ -2677,6 +2682,9 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
} }
} }
} }
is_selecting_text = false;
click_select_held->stop();
} }
} }
@ -2865,13 +2873,37 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> m = p_event; Ref<InputEventMouseMotion> m = p_event;
if (m.is_valid()) { if (m.is_valid()) {
local_mouse_pos = get_local_mouse_position();
last_clamped_mouse_pos = local_mouse_pos.clamp(Vector2(), get_size());
}
}
void RichTextLabel::_update_selection() {
ItemFrame *c_frame = nullptr; ItemFrame *c_frame = nullptr;
int c_line = 0; int c_line = 0;
Item *c_item = nullptr; Item *c_item = nullptr;
int c_index = 0; int c_index = 0;
bool outside; bool outside;
_find_click(main, m->get_position(), &c_frame, &c_line, &c_item, &c_index, &outside, false); // Handle auto scrolling.
const Size2 size = get_size();
if (!(local_mouse_pos.x >= 0.0 && local_mouse_pos.y >= 0.0 &&
local_mouse_pos.x < size.x && local_mouse_pos.y < size.y)) {
real_t scroll_delta = 0.0;
if (local_mouse_pos.y < 0) {
scroll_delta = -auto_scroll_speed * (1 - (local_mouse_pos.y / 15.0));
} else if (local_mouse_pos.y > size.y) {
scroll_delta = auto_scroll_speed * (1 + (local_mouse_pos.y - size.y) / 15.0);
}
if (scroll_delta != 0.0) {
vscroll->scroll(scroll_delta);
queue_redraw();
}
}
// Update selection area.
_find_click(main, last_clamped_mouse_pos, &c_frame, &c_line, &c_item, &c_index, &outside, false);
if (selection.click_item && c_item) { if (selection.click_item && c_item) {
selection.from_frame = selection.click_frame; selection.from_frame = selection.click_frame;
selection.from_line = selection.click_line; selection.from_line = selection.click_line;
@ -2930,7 +2962,8 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
queue_redraw(); queue_redraw();
} }
_find_click(main, m->get_position(), nullptr, nullptr, &c_item, nullptr, &outside, true); // Update meta hovering.
_find_click(main, local_mouse_pos, nullptr, nullptr, &c_item, nullptr, &outside, true);
Variant meta; Variant meta;
ItemMeta *item_meta; ItemMeta *item_meta;
ItemMeta *prev_meta = meta_hovering; ItemMeta *prev_meta = meta_hovering;
@ -2955,7 +2988,6 @@ void RichTextLabel::gui_input(const Ref<InputEvent> &p_event) {
} }
} }
} }
}
String RichTextLabel::get_tooltip(const Point2 &p_pos) const { String RichTextLabel::get_tooltip(const Point2 &p_pos) const {
Item *c_item = nullptr; Item *c_item = nullptr;
@ -7783,6 +7815,11 @@ RichTextLabel::RichTextLabel(const String &p_text) {
parsing_bbcode.store(false); parsing_bbcode.store(false);
set_clip_contents(true); set_clip_contents(true);
click_select_held = memnew(Timer);
add_child(click_select_held, false, INTERNAL_MODE_FRONT);
click_select_held->set_wait_time(0.05);
click_select_held->connect("timeout", callable_mp(this, &RichTextLabel::_update_selection));
} }
RichTextLabel::~RichTextLabel() { RichTextLabel::~RichTextLabel() {

View file

@ -36,6 +36,10 @@
#include "scene/gui/scroll_bar.h" #include "scene/gui/scroll_bar.h"
#include "scene/resources/text_paragraph.h" #include "scene/resources/text_paragraph.h"
#ifdef TOOLS_ENABLED
#include "editor/themes/editor_scale.h"
#endif
class CharFXTransform; class CharFXTransform;
class RichTextEffect; class RichTextEffect;
@ -667,6 +671,17 @@ private:
void _scroll_changed(double); void _scroll_changed(double);
int _find_first_line(int p_from, int p_to, int p_vofs) const; int _find_first_line(int p_from, int p_to, int p_vofs) const;
#ifdef TOOLS_ENABLED
const real_t auto_scroll_speed = EDSCALE * 2.0f;
#else
const real_t auto_scroll_speed = 2.0f;
#endif
Vector2 last_clamped_mouse_pos;
Timer *click_select_held = nullptr;
Vector2 local_mouse_pos;
bool is_selecting_text = false;
void _update_selection();
_FORCE_INLINE_ float _calculate_line_vertical_offset(const Line &line) const; _FORCE_INLINE_ float _calculate_line_vertical_offset(const Line &line) const;
virtual void gui_input(const Ref<InputEvent> &p_event) override; virtual void gui_input(const Ref<InputEvent> &p_event) override;