Browse Source

Text input: Add Ctrl/Alt word navigation

pull/6749/head
Gleb Mazovetskiy 2 years ago
parent
commit
2b0876edfa
  1. 19
      Source/DiabloUI/text_input.cpp
  2. 71
      Source/DiabloUI/text_input.hpp

19
Source/DiabloUI/text_input.cpp

@ -25,13 +25,16 @@ bool HandleInputEvent(const SDL_Event &event, TextInputState &state,
tl::function_ref<bool(std::string_view)> typeFn,
[[maybe_unused]] tl::function_ref<bool(std::string_view)> assignFn)
{
const bool isShift = (SDL_GetModState() & KMOD_SHIFT) != 0;
const auto modState = SDL_GetModState();
const bool isCtrl = (modState & KMOD_CTRL) != 0;
const bool isAlt = (modState & KMOD_ALT) != 0;
const bool isShift = (modState & KMOD_SHIFT) != 0;
switch (event.type) {
case SDL_KEYDOWN: {
switch (event.key.keysym.sym) {
#ifndef USE_SDL1
case SDLK_c:
if ((SDL_GetModState() & KMOD_CTRL) != 0) {
if (isCtrl) {
const std::string selectedText { state.selectedText() };
if (SDL_SetClipboardText(selectedText.c_str()) < 0) {
Log("{}", SDL_GetError());
@ -39,7 +42,7 @@ bool HandleInputEvent(const SDL_Event &event, TextInputState &state,
}
return true;
case SDLK_x:
if ((SDL_GetModState() & KMOD_CTRL) != 0) {
if (isCtrl) {
const std::string selectedText { state.selectedText() };
if (SDL_SetClipboardText(selectedText.c_str()) < 0) {
Log("{}", SDL_GetError());
@ -49,7 +52,7 @@ bool HandleInputEvent(const SDL_Event &event, TextInputState &state,
}
return true;
case SDLK_v:
if ((SDL_GetModState() & KMOD_CTRL) != 0) {
if (isCtrl) {
if (SDL_HasClipboardText() == SDL_TRUE) {
std::unique_ptr<char, SDLFreeDeleter<char>> clipboard { SDL_GetClipboardText() };
if (clipboard == nullptr || *clipboard == '\0') {
@ -62,16 +65,16 @@ bool HandleInputEvent(const SDL_Event &event, TextInputState &state,
return true;
#endif
case SDLK_BACKSPACE:
state.backspace();
state.backspace(/*word=*/isCtrl || isAlt);
return true;
case SDLK_DELETE:
state.del();
state.del(/*word=*/isCtrl || isAlt);
return true;
case SDLK_LEFT:
isShift ? state.moveSelectCursorLeft() : state.moveCursorLeft();
isShift ? state.moveSelectCursorLeft(/*word=*/isCtrl || isAlt) : state.moveCursorLeft(/*word=*/isCtrl || isAlt);
return true;
case SDLK_RIGHT:
isShift ? state.moveSelectCursorRight() : state.moveCursorRight();
isShift ? state.moveSelectCursorRight(/*word=*/isCtrl || isAlt) : state.moveCursorRight(/*word=*/isCtrl || isAlt);
return true;
case SDLK_HOME:
isShift ? state.setSelectCursorToStart() : state.setCursorToStart();

71
Source/DiabloUI/text_input.hpp

@ -206,33 +206,28 @@ public:
cursor_->position += value_.size() - prevSize;
}
void backspace()
void backspace(bool word)
{
if (cursor_->selection.empty()) {
if (cursor_->position == 0)
return;
cursor_->selection.begin = FindLastUtf8Symbols(beforeCursor());
cursor_->selection.begin = prevPosition(word);
cursor_->selection.end = cursor_->position;
}
eraseSelection();
}
void del()
void del(bool word)
{
if (cursor_->selection.empty()) {
if (cursor_->position == value_.size())
return;
cursor_->selection.begin = cursor_->position;
cursor_->selection.end = cursor_->position + Utf8CodePointLen(afterCursor().data());
cursor_->selection.end = nextPosition(word);
}
eraseSelection();
}
void delSelection()
{
value_.erase(cursor_->selection.begin, cursor_->selection.size());
}
void setCursorToStart()
{
cursor_->position = 0;
@ -265,20 +260,20 @@ public:
cursor_->selection.end = cursor_->position = value_.size();
}
void moveCursorLeft()
void moveCursorLeft(bool word)
{
cursor_->selection.clear();
if (cursor_->position == 0)
return;
const size_t newPosition = FindLastUtf8Symbols(beforeCursor());
const size_t newPosition = prevPosition(word);
cursor_->position = newPosition;
}
void moveSelectCursorLeft()
void moveSelectCursorLeft(bool word)
{
if (cursor_->position == 0)
return;
const size_t newPosition = FindLastUtf8Symbols(beforeCursor());
const size_t newPosition = prevPosition(word);
if (cursor_->selection.empty()) {
cursor_->selection.begin = newPosition;
cursor_->selection.end = cursor_->position;
@ -290,20 +285,20 @@ public:
cursor_->position = newPosition;
}
void moveCursorRight()
void moveCursorRight(bool word)
{
cursor_->selection.clear();
if (cursor_->position == value_.size())
return;
const size_t newPosition = cursor_->position + Utf8CodePointLen(afterCursor().data());
const size_t newPosition = nextPosition(word);
cursor_->position = newPosition;
}
void moveSelectCursorRight()
void moveSelectCursorRight(bool word)
{
if (cursor_->position == value_.size())
return;
const size_t newPosition = cursor_->position + Utf8CodePointLen(afterCursor().data());
const size_t newPosition = nextPosition(word);
if (cursor_->selection.empty()) {
cursor_->selection.begin = cursor_->position;
cursor_->selection.end = newPosition;
@ -316,6 +311,48 @@ public:
}
private:
[[nodiscard]] static bool isWordSeparator(unsigned char c)
{
const bool isAsciiWordChar = (c >= '0' && c <= '9')
|| (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_';
return c <= '\x7E' && !isAsciiWordChar;
}
[[nodiscard]] size_t prevPosition(bool word) const
{
const std::string_view str = beforeCursor();
size_t pos = FindLastUtf8Symbols(str);
if (!word)
return pos;
while (pos > 0 && isWordSeparator(str[pos])) {
pos = FindLastUtf8Symbols({ str.data(), pos });
}
while (pos > 0) {
const size_t prevPos = FindLastUtf8Symbols({ str.data(), pos });
if (isWordSeparator(str[prevPos]))
break;
pos = prevPos;
}
return pos;
}
[[nodiscard]] size_t nextPosition(bool word) const
{
const std::string_view str = afterCursor();
size_t pos = Utf8CodePointLen(str.data());
if (!word)
return cursor_->position + pos;
while (pos < str.size() && isWordSeparator(str[pos])) {
pos += Utf8CodePointLen(str.data() + pos);
}
while (pos < str.size()) {
pos += Utf8CodePointLen(str.data() + pos);
if (isWordSeparator(str[pos]))
break;
}
return cursor_->position + pos;
}
[[nodiscard]] std::string_view beforeCursor() const
{
return value().substr(0, cursor_->position);

Loading…
Cancel
Save