diff --git a/src/gui/guiEditBox.cpp b/src/gui/guiEditBox.cpp index a5f2581f74..918af9e96e 100644 --- a/src/gui/guiEditBox.cpp +++ b/src/gui/guiEditBox.cpp @@ -279,6 +279,11 @@ bool GUIEditBox::processKey(const SEvent &event) new_mark_end = 0; } break; + case KEY_LEFT: + case KEY_RIGHT: + processKeyLR(event.KeyInput, new_mark_begin, new_mark_end); + m_blink_start_time = porting::getTimeMs(); + break; default: return false; } @@ -335,37 +340,8 @@ bool GUIEditBox::processKey(const SEvent &event) } return true; case KEY_LEFT: - if (event.KeyInput.Shift) { - if (m_cursor_pos > 0) { - if (m_mark_begin == m_mark_end) - new_mark_begin = m_cursor_pos; - - new_mark_end = m_cursor_pos - 1; - } - } else { - new_mark_begin = 0; - new_mark_end = 0; - } - - if (m_cursor_pos > 0) - m_cursor_pos--; - m_blink_start_time = porting::getTimeMs(); - break; case KEY_RIGHT: - if (event.KeyInput.Shift) { - if (Text.size() > (u32)m_cursor_pos) { - if (m_mark_begin == m_mark_end) - new_mark_begin = m_cursor_pos; - - new_mark_end = m_cursor_pos + 1; - } - } else { - new_mark_begin = 0; - new_mark_end = 0; - } - - if (Text.size() > (u32)m_cursor_pos) - m_cursor_pos++; + processKeyLR(event.KeyInput, new_mark_begin, new_mark_end); m_blink_start_time = porting::getTimeMs(); break; case KEY_UP: @@ -436,6 +412,54 @@ bool GUIEditBox::processKey(const SEvent &event) return true; } +void GUIEditBox::processKeyLR(const SEvent::SKeyInput &input, s32 &new_mark_begin, + s32 &new_mark_end) +{ + const s8 dir = input.Key == KEY_RIGHT ? 1 : -1; + + s32 new_pos = m_cursor_pos; + if (input.Control) { + // Advance to next/previous word + wchar_t prev_c = L'\0'; + for (s32 i = new_pos; i >= 0 && i <= (s32)Text.size(); i += dir) { + // This only handles Latin characters. + const wchar_t c = Text[i]; + + new_pos = i; + if (std::abs(i - m_cursor_pos) > 2) { + // End of word + if (!std::iswspace(prev_c) && std::iswspace(c)) + break; + // End of a sentence. + if (std::iswpunct(prev_c) && !std::iswpunct(c)) + break; + } + prev_c = c; + } + } else { + // Advance by +1/-1 character + new_pos += dir; + } + + if (!input.Shift) { + // Reset selection + new_mark_begin = 0; + new_mark_end = 0; + } + + if (new_pos >= 0 && new_pos <= (s32)Text.size()) { + // Update cursor (and selection) + if (input.Shift) { + if (m_mark_begin == m_mark_end) + new_mark_begin = m_cursor_pos; + + new_mark_end = new_pos; + } + + m_cursor_pos = new_pos; + } +} + bool GUIEditBox::onKeyUp(const SEvent &event, s32 &mark_begin, s32 &mark_end) { if (m_multiline || (m_word_wrap && m_broken_text.size() > 1)) { diff --git a/src/gui/guiEditBox.h b/src/gui/guiEditBox.h index be18e19a62..8d4698b308 100644 --- a/src/gui/guiEditBox.h +++ b/src/gui/guiEditBox.h @@ -135,6 +135,10 @@ protected: virtual s32 getCursorPos(s32 x, s32 y) = 0; bool processKey(const SEvent &event); + //! KEY_LEFT / KEY_RIGHT inputs + void processKeyLR(const SEvent::SKeyInput &input, s32 &new_mark_begin, + s32 &new_mark_end); + virtual void inputString(const core::stringw &str); virtual void inputChar(wchar_t c);