From b80bc553dd52259eee4c25eb7652020e75d9e814 Mon Sep 17 00:00:00 2001 From: Bernhard Liebl Date: Sat, 23 Dec 2017 09:59:54 +0100 Subject: [PATCH] Double-click word selection for RichTextLabel (i.e. docs) --- core/ustring.cpp | 34 +++++++++++++++++++++++++ core/ustring.h | 3 +++ editor/editor_help.cpp | 2 +- scene/gui/rich_text_label.cpp | 28 ++++++++++++++++++++ scene/gui/text_edit.cpp | 48 ++++++++--------------------------- 5 files changed, 76 insertions(+), 39 deletions(-) diff --git a/core/ustring.cpp b/core/ustring.cpp index ceafe209ea..ece3928298 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -56,6 +56,40 @@ #define IS_DIGIT(m_d) ((m_d) >= '0' && (m_d) <= '9') #define IS_HEX_DIGIT(m_d) (((m_d) >= '0' && (m_d) <= '9') || ((m_d) >= 'a' && (m_d) <= 'f') || ((m_d) >= 'A' && (m_d) <= 'F')) +bool is_symbol(CharType c) { + return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' '); +} + +bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end) { + + const String &s = p_s; + int beg = CLAMP(p_col, 0, s.length()); + int end = beg; + + if (s[beg] > 32 || beg == s.length()) { + + bool symbol = beg < s.length() && is_symbol(s[beg]); + + while (beg > 0 && s[beg - 1] > 32 && (symbol == is_symbol(s[beg - 1]))) { + beg--; + } + while (end < s.length() && s[end + 1] > 32 && (symbol == is_symbol(s[end + 1]))) { + end++; + } + + if (end < s.length()) + end += 1; + + r_beg = beg; + r_end = end; + + return true; + } else { + + return false; + } +} + /** STRING **/ bool CharString::operator<(const CharString &p_right) const { diff --git a/core/ustring.h b/core/ustring.h index 73537bfd13..de308ff917 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -295,4 +295,7 @@ String TTR(const String &); //tool or regular translate String RTR(const String &); +bool is_symbol(CharType c); +bool select_word(const String &p_s, int p_col, int &r_beg, int &r_end); + #endif diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 46badc8c86..ce729a9ee2 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -630,7 +630,7 @@ void EditorHelp::_class_desc_input(const Ref &p_input) { Ref mb = p_input; - if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == 1) { + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == 1 && !mb->is_doubleclick()) { class_desc->set_selection_enabled(false); class_desc->set_selection_enabled(true); } diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 6fbc58a38a..7fe8a01cda 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -815,7 +815,35 @@ void RichTextLabel::_gui_input(Ref p_event) { } } } + } else if (b->is_pressed() && b->is_doubleclick() && selection.enabled) { + //doubleclick: select word + int line = 0; + Item *item = NULL; + bool outside; + + _find_click(main, b->get_position(), &item, &line, &outside); + + while (item && item->type != ITEM_TEXT) { + + item = _get_next_item(item, true); + } + + if (item && item->type == ITEM_TEXT) { + + String itext = static_cast(item)->text; + + int beg, end; + if (select_word(itext, line, beg, end)) { + + selection.from = item; + selection.to = item; + selection.from_char = beg; + selection.to_char = end - 1; + selection.active = true; + update(); + } + } } else if (!b->is_pressed()) { selection.click = NULL; diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 07f1bdf8e5..64d238fb2c 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -42,16 +42,16 @@ #define TAB_PIXELS +inline bool _is_symbol(CharType c) { + + return is_symbol(c); +} + static bool _is_text_char(CharType c) { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'; } -static bool _is_symbol(CharType c) { - - return c != '_' && ((c >= '!' && c <= '/') || (c >= ':' && c <= '@') || (c >= '[' && c <= '`') || (c >= '{' && c <= '~') || c == '\t' || c == ' '); -} - static bool _is_whitespace(CharType c) { return c == '\t' || c == ' '; } @@ -1962,7 +1962,7 @@ void TextEdit::_gui_input(const Ref &p_gui_input) { } else if (mb->is_doubleclick() && text[cursor.line].length()) { - //doubleclick select world + //doubleclick select word selection.selecting_mode = Selection::MODE_WORD; _update_selection_mode_word(); last_dblclk = OS::get_singleton()->get_ticks_msec(); @@ -5181,12 +5181,8 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const { String s = text[row]; if (s.length() == 0) return ""; - int beg = CLAMP(col, 0, s.length()); - int end = beg; - - if (s[beg] > 32 || beg == s.length()) { - - bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this + int beg, end; + if (select_word(s, col, beg, end)) { bool inside_quotes = false; int qbegin = 0, qend = 0; @@ -5205,16 +5201,6 @@ String TextEdit::get_word_at_pos(const Vector2 &p_pos) const { } } - while (beg > 0 && s[beg - 1] > 32 && (symbol == _is_symbol(s[beg - 1]))) { - beg--; - } - while (end < s.length() && s[end + 1] > 32 && (symbol == _is_symbol(s[end + 1]))) { - end++; - } - - if (end < s.length()) - end += 1; - return s.substr(beg, end - beg); } @@ -5231,22 +5217,8 @@ String TextEdit::get_tooltip(const Point2 &p_pos) const { String s = text[row]; if (s.length() == 0) return Control::get_tooltip(p_pos); - int beg = CLAMP(col, 0, s.length()); - int end = beg; - - if (s[beg] > 32 || beg == s.length()) { - - bool symbol = beg < s.length() && _is_symbol(s[beg]); //not sure if right but most editors behave like this - - while (beg > 0 && s[beg - 1] > 32 && (symbol == _is_symbol(s[beg - 1]))) { - beg--; - } - while (end < s.length() && s[end + 1] > 32 && (symbol == _is_symbol(s[end + 1]))) { - end++; - } - - if (end < s.length()) - end += 1; + int beg, end; + if (select_word(s, col, beg, end)) { String tt = tooltip_obj->call(tooltip_func, s.substr(beg, end - beg), tooltip_ud);