1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-09-15 18:57:08 +00:00

Formspec: Implement Ctrl+Shift+Left/Right text selection (#16455)

This is a quality-of-life improvement to edit text more easily.
This commit is contained in:
SmallJoker 2025-09-04 18:58:46 +02:00 committed by GitHub
parent 024e1d2d27
commit d24a7001ab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 58 additions and 30 deletions

View file

@ -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)) {

View file

@ -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);