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>
|
|
|
|
#include <base/tl/base.h>
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
#include "lineinput.h"
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <engine/keys.h>
|
2008-08-27 15:48:50 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
CLineInput::CLineInput()
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
Clear();
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CLineInput::Clear()
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2021-11-24 22:31:40 +00:00
|
|
|
Set("");
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CLineInput::Set(const char *pString)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2021-09-13 09:47:47 +00:00
|
|
|
str_copy(m_aStr, pString, sizeof(m_aStr));
|
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;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 23:00:20 +00:00
|
|
|
void CLineInput::SetRange(const char *pString, int Begin, int End)
|
|
|
|
{
|
|
|
|
if(Begin > End)
|
|
|
|
swap(Begin, End);
|
|
|
|
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';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-08-15 05:16:06 +00:00
|
|
|
void CLineInput::Editing(const char *pString, int Cursor)
|
|
|
|
{
|
2022-03-31 10:44:27 +00:00
|
|
|
str_copy(m_aDisplayStr, m_aStr, sizeof(m_aDisplayStr));
|
2020-10-25 17:44:10 +00:00
|
|
|
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;
|
2016-08-15 05:16:06 +00:00
|
|
|
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];
|
2016-08-15 05:16:06 +00:00
|
|
|
for(int i = 0; i < FillCharLen; i++)
|
2022-03-31 10:44:27 +00:00
|
|
|
m_aDisplayStr[m_CursorPos + i] = aEditingText[i];
|
2022-03-31 10:44:49 +00:00
|
|
|
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;
|
2016-08-15 05:16:06 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 23:04:59 +00:00
|
|
|
void CLineInput::Insert(const char *pString, int Begin)
|
|
|
|
{
|
|
|
|
SetRange(pString, Begin, Begin);
|
|
|
|
}
|
|
|
|
|
2021-11-24 23:03:35 +00:00
|
|
|
void CLineInput::Append(const char *pString)
|
2015-08-25 12:24:46 +00:00
|
|
|
{
|
2021-11-24 23:04:59 +00:00
|
|
|
Insert(pString, m_Len);
|
2015-08-25 12:24:46 +00:00
|
|
|
}
|
|
|
|
|
2021-09-16 14:50:17 +00:00
|
|
|
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)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
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;
|
2021-09-16 14:50:17 +00:00
|
|
|
int32_t Changes = 0;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
if(CursorPos > Len)
|
|
|
|
CursorPos = Len;
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(Event.m_Flags & IInput::FLAG_TEXT)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2016-04-30 02:02:32 +00:00
|
|
|
// gather string stats
|
|
|
|
int CharCount = 0;
|
|
|
|
int CharSize = 0;
|
2021-11-24 22:39:34 +00:00
|
|
|
str_utf8_stats(Event.m_aText, MAX_SIZE, MAX_CHARS, &CharSize, &CharCount);
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2016-04-30 02:02:32 +00:00
|
|
|
// add new string
|
|
|
|
if(CharCount)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
if(Len + CharSize < StrMaxSize && CursorPos + CharSize < StrMaxSize && NumChars + CharCount < StrMaxChars)
|
2016-04-30 02:02:32 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +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++)
|
2020-09-26 19:41:58 +00:00
|
|
|
pStr[CursorPos + i] = Event.m_aText[i];
|
2016-04-30 02:02:32 +00:00
|
|
|
CursorPos += CharSize;
|
|
|
|
Len += CharSize;
|
|
|
|
NumChars += CharCount;
|
2021-09-16 14:50:17 +00:00
|
|
|
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_STRING;
|
2016-04-30 02:02:32 +00:00
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
if(Event.m_Flags & IInput::FLAG_PRESS)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2016-04-30 02:02:32 +00:00
|
|
|
int Key = Event.m_Key;
|
2021-09-16 14:50:17 +00:00
|
|
|
if(Key == KEY_BACKSPACE)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2021-09-16 14:50:17 +00:00
|
|
|
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;
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2021-09-16 14:50:17 +00:00
|
|
|
else if(Key == KEY_DELETE)
|
2008-08-27 15:48:50 +00:00
|
|
|
{
|
2021-09-16 14:50:17 +00:00
|
|
|
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)
|
|
|
|
{
|
2021-12-18 11:23:20 +00:00
|
|
|
if(ModifierKey == KEY_LCTRL || ModifierKey == KEY_RCTRL || ModifierKey == KEY_LGUI || ModifierKey == KEY_RGUI)
|
2021-09-16 14:50:17 +00:00
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2021-12-18 11:23:20 +00:00
|
|
|
if(ModifierKey == KEY_LCTRL || ModifierKey == KEY_RCTRL || ModifierKey == KEY_LGUI || ModifierKey == KEY_RGUI)
|
2021-09-16 14:50:17 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2016-04-30 02:02:32 +00:00
|
|
|
else if(Key == KEY_HOME)
|
2021-09-16 14:50:17 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CursorPos = 0;
|
2021-09-16 14:50:17 +00:00
|
|
|
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_WARP_CURSOR;
|
|
|
|
}
|
2016-04-30 02:02:32 +00:00
|
|
|
else if(Key == KEY_END)
|
2021-09-16 14:50:17 +00:00
|
|
|
{
|
2010-05-29 07:25:38 +00:00
|
|
|
CursorPos = Len;
|
2021-09-16 14:50:17 +00:00
|
|
|
Changes |= ELineInputChanges::LINE_INPUT_CHANGE_WARP_CURSOR;
|
|
|
|
}
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|
2011-04-13 18:37:12 +00:00
|
|
|
|
2013-04-01 18:30:58 +00:00
|
|
|
*pNumCharsPtr = NumChars;
|
2010-05-29 07:25:38 +00:00
|
|
|
*pCursorPosPtr = CursorPos;
|
|
|
|
*pStrLenPtr = Len;
|
|
|
|
|
|
|
|
return Changes;
|
2009-06-13 08:22:37 +00:00
|
|
|
}
|
|
|
|
|
2010-05-29 07:25:38 +00:00
|
|
|
void CLineInput::ProcessInput(IInput::CEvent e)
|
2009-06-13 08:22:37 +00:00
|
|
|
{
|
2021-09-16 14:50:17 +00:00
|
|
|
Manipulate(e, m_aStr, MAX_SIZE, MAX_CHARS, &m_Len, &m_CursorPos, &m_NumChars, 0, 0);
|
2008-08-27 15:48:50 +00:00
|
|
|
}
|