ddnet/src/game/client/lineinput.cpp

225 lines
6.8 KiB
C++
Raw Normal View History

2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
2021-11-24 23:00:20 +00:00
#include <base/math.h>
#include <base/system.h>
2010-05-29 07:25:38 +00:00
#include "lineinput.h"
#include <engine/keys.h>
2010-05-29 07:25:38 +00:00
CLineInput::CLineInput()
{
2010-05-29 07:25:38 +00:00
Clear();
}
2010-05-29 07:25:38 +00:00
void CLineInput::Clear()
{
2021-11-24 22:31:40 +00:00
Set("");
}
2010-05-29 07:25:38 +00:00
void CLineInput::Set(const char *pString)
{
2022-07-09 16:14:56 +00:00
str_copy(m_aStr, pString);
2021-11-24 22:29:09 +00:00
str_utf8_stats(m_aStr, MAX_SIZE, MAX_CHARS, &m_Len, &m_NumChars);
2010-05-29 07:25:38 +00:00
m_CursorPos = m_Len;
}
2021-11-24 23:00:20 +00:00
void CLineInput::SetRange(const char *pString, int Begin, int End)
{
if(Begin > End)
2022-05-15 17:25:36 +00:00
std::swap(Begin, End);
2021-11-24 23:00:20 +00:00
Begin = clamp(Begin, 0, m_Len);
End = clamp(End, 0, m_Len);
int RemovedCharSize, RemovedCharCount;
str_utf8_stats(m_aStr + Begin, End - Begin + 1, MAX_CHARS, &RemovedCharSize, &RemovedCharCount);
int AddedCharSize, AddedCharCount;
str_utf8_stats(pString, MAX_SIZE - m_Len + RemovedCharSize, MAX_CHARS - m_NumChars + RemovedCharCount, &AddedCharSize, &AddedCharCount);
if(RemovedCharSize || AddedCharSize)
{
if(AddedCharSize < RemovedCharSize)
{
if(AddedCharSize)
mem_copy(m_aStr + Begin, pString, AddedCharSize);
mem_move(m_aStr + Begin + AddedCharSize, m_aStr + Begin + RemovedCharSize, m_Len - Begin - AddedCharSize);
}
else if(AddedCharSize > RemovedCharSize)
mem_move(m_aStr + End + AddedCharSize - RemovedCharSize, m_aStr + End, m_Len - End);
if(AddedCharSize >= RemovedCharSize)
mem_copy(m_aStr + Begin, pString, AddedCharSize);
m_CursorPos = End - RemovedCharSize + AddedCharSize;
m_Len += AddedCharSize - RemovedCharSize;
m_NumChars += AddedCharCount - RemovedCharCount;
m_aStr[m_Len] = '\0';
}
}
void CLineInput::Editing(const char *pString, int Cursor)
{
2022-07-09 16:14:56 +00:00
str_copy(m_aDisplayStr, m_aStr);
char aEditingText[IInput::INPUT_TEXT_SIZE + 2];
str_format(aEditingText, sizeof(aEditingText), "[%s]", pString);
int NewTextLen = str_length(aEditingText);
2022-03-31 10:44:27 +00:00
int CharsLeft = (int)sizeof(m_aDisplayStr) - str_length(m_aDisplayStr) - 1;
int FillCharLen = NewTextLen < CharsLeft ? NewTextLen : CharsLeft;
2022-03-31 10:44:27 +00:00
for(int i = str_length(m_aDisplayStr) - 1; i >= m_CursorPos; i--)
m_aDisplayStr[i + FillCharLen] = m_aDisplayStr[i];
for(int i = 0; i < FillCharLen; i++)
2022-03-31 10:44:27 +00:00
m_aDisplayStr[m_CursorPos + i] = aEditingText[i];
m_aDisplayStr[m_CursorPos + FillCharLen] = '\0';
2022-03-31 10:44:27 +00:00
m_FakeLen = str_length(m_aDisplayStr);
2017-02-21 16:10:08 +00:00
m_FakeCursorPos = m_CursorPos + Cursor + 1;
}
2021-11-24 23:04:59 +00:00
void CLineInput::Insert(const char *pString, int Begin)
{
SetRange(pString, Begin, Begin);
}
void CLineInput::Append(const char *pString)
{
2021-11-24 23:04:59 +00:00
Insert(pString, m_Len);
}
static bool IsNotAWordChar(signed char c)
{
return (c > 0 && c < '0') || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || (c > 'z'); // all non chars in ascii -- random
}
int32_t CLineInput::Manipulate(IInput::CEvent Event, char *pStr, int StrMaxSize, int StrMaxChars, int *pStrLenPtr, int *pCursorPosPtr, int *pNumCharsPtr, int32_t ModifyFlags, int ModifierKey)
{
2013-04-01 18:30:58 +00:00
int NumChars = *pNumCharsPtr;
2010-05-29 07:25:38 +00:00
int CursorPos = *pCursorPosPtr;
int Len = *pStrLenPtr;
int32_t Changes = 0;
2010-05-29 07:25:38 +00:00
if(CursorPos > Len)
CursorPos = Len;
if(Event.m_Flags & IInput::FLAG_TEXT)
{
2016-04-30 02:02:32 +00:00
// gather string stats
int CharCount = 0;
int CharSize = 0;
str_utf8_stats(Event.m_aText, MAX_SIZE, MAX_CHARS, &CharSize, &CharCount);
2016-04-30 02:02:32 +00:00
// add new string
if(CharCount)
{
if(Len + CharSize < StrMaxSize && CursorPos + CharSize < StrMaxSize && NumChars + CharCount < StrMaxChars)
2016-04-30 02:02:32 +00:00
{
mem_move(pStr + CursorPos + CharSize, pStr + CursorPos, Len - CursorPos + 1); // +1 == null term
2016-04-30 02:02:32 +00:00
for(int i = 0; i < CharSize; i++)
pStr[CursorPos + i] = Event.m_aText[i];
2016-04-30 02:02:32 +00:00
CursorPos += CharSize;
Len += CharSize;
NumChars += CharCount;
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_STRING;
2016-04-30 02:02:32 +00:00
}
}
}
if(Event.m_Flags & IInput::FLAG_PRESS)
{
2016-04-30 02:02:32 +00:00
int Key = Event.m_Key;
if(Key == KEY_BACKSPACE)
{
if((ModifyFlags & LINE_INPUT_MODIFY_DONT_DELETE) == 0 && CursorPos > 0)
{
int NewCursorPos = str_utf8_rewind(pStr, CursorPos);
int CharSize = CursorPos - NewCursorPos;
mem_move(pStr + NewCursorPos, pStr + CursorPos, Len - NewCursorPos - CharSize + 1); // +1 == null term
CursorPos = NewCursorPos;
Len -= CharSize;
if(CharSize > 0)
--NumChars;
}
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_CHARACTERS_DELETE;
}
else if(Key == KEY_DELETE)
{
if((ModifyFlags & LINE_INPUT_MODIFY_DONT_DELETE) == 0 && CursorPos < Len)
{
int p = str_utf8_forward(pStr, CursorPos);
int CharSize = p - CursorPos;
mem_move(pStr + CursorPos, pStr + CursorPos + CharSize, Len - CursorPos - CharSize + 1); // +1 == null term
Len -= CharSize;
if(CharSize > 0)
--NumChars;
}
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_CHARACTERS_DELETE;
}
else if(Key == KEY_LEFT)
{
if(ModifierKey == KEY_LCTRL || ModifierKey == KEY_RCTRL || ModifierKey == KEY_LGUI || ModifierKey == KEY_RGUI)
{
bool MovedCursor = false;
int OldCursorPos = CursorPos;
CursorPos = str_utf8_rewind(pStr, CursorPos);
if(OldCursorPos != CursorPos)
MovedCursor = true;
bool WasNonWordChar = IsNotAWordChar(pStr[CursorPos]);
while((!WasNonWordChar && !IsNotAWordChar(pStr[CursorPos])) || (WasNonWordChar && IsNotAWordChar(pStr[CursorPos])))
{
CursorPos = str_utf8_rewind(pStr, CursorPos);
if(CursorPos == 0)
break;
}
if(MovedCursor && ((!WasNonWordChar && IsNotAWordChar(pStr[CursorPos])) || (WasNonWordChar && !IsNotAWordChar(pStr[CursorPos]))))
CursorPos = str_utf8_forward(pStr, CursorPos);
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_WARP_CURSOR;
}
else
{
if(CursorPos > 0)
CursorPos = str_utf8_rewind(pStr, CursorPos);
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_CURSOR;
}
}
else if(Key == KEY_RIGHT)
{
if(ModifierKey == KEY_LCTRL || ModifierKey == KEY_RCTRL || ModifierKey == KEY_LGUI || ModifierKey == KEY_RGUI)
{
bool WasNonWordChar = IsNotAWordChar(pStr[CursorPos]);
while((!WasNonWordChar && !IsNotAWordChar(pStr[CursorPos])) || (WasNonWordChar && IsNotAWordChar(pStr[CursorPos])))
{
CursorPos = str_utf8_forward(pStr, CursorPos);
if(CursorPos >= Len)
break;
}
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_WARP_CURSOR;
}
else
{
if(CursorPos < Len)
CursorPos = str_utf8_forward(pStr, CursorPos);
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_CURSOR;
}
}
2016-04-30 02:02:32 +00:00
else if(Key == KEY_HOME)
{
2010-05-29 07:25:38 +00:00
CursorPos = 0;
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_WARP_CURSOR;
}
2016-04-30 02:02:32 +00:00
else if(Key == KEY_END)
{
2010-05-29 07:25:38 +00:00
CursorPos = Len;
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_WARP_CURSOR;
}
}
2013-04-01 18:30:58 +00:00
*pNumCharsPtr = NumChars;
2010-05-29 07:25:38 +00:00
*pCursorPosPtr = CursorPos;
*pStrLenPtr = Len;
return Changes;
}
2010-05-29 07:25:38 +00:00
void CLineInput::ProcessInput(IInput::CEvent e)
{
Manipulate(e, m_aStr, MAX_SIZE, MAX_CHARS, &m_Len, &m_CursorPos, &m_NumChars, 0, 0);
}