/* (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. */
#ifndef GAME_CLIENT_LINEINPUT_H
#define GAME_CLIENT_LINEINPUT_H
#include
#include
#include
#include
#include
#include
enum class EInputPriority
{
NONE = 0,
UI,
CHAT,
CONSOLE,
};
// line input helper
class CLineInput
{
public:
struct SMouseSelection
{
bool m_Selecting = false;
vec2 m_PressMouse = vec2(0.0f, 0.0f);
vec2 m_ReleaseMouse = vec2(0.0f, 0.0f);
vec2 m_Offset = vec2(0.0f, 0.0f);
};
typedef std::function FClipboardLineCallback;
private:
static IClient *ms_pClient;
static IGraphics *ms_pGraphics;
static IInput *ms_pInput;
static ITextRender *ms_pTextRender;
static IClient *Client() { return ms_pClient; }
static IGraphics *Graphics() { return ms_pGraphics; }
static IInput *Input() { return ms_pInput; }
static ITextRender *TextRender() { return ms_pTextRender; }
static CLineInput *ms_pActiveInput;
static EInputPriority ms_ActiveInputPriority;
static vec2 ms_CompositionWindowPosition;
static float ms_CompositionLineHeight;
static char ms_aStars[128];
char *m_pStr = nullptr; // explicitly set to nullptr outside of contructor, so SetBuffer works in this case
size_t m_MaxSize;
size_t m_MaxChars;
size_t m_Len;
size_t m_NumChars;
size_t m_CursorPos;
size_t m_SelectionStart;
size_t m_SelectionEnd;
float m_ScrollOffset;
float m_ScrollOffsetChange;
vec2 m_CaretPosition;
SMouseSelection m_MouseSelection;
size_t m_LastCompositionCursorPos;
bool m_Hidden;
const char *m_pEmptyText;
FClipboardLineCallback m_pfnClipboardLineCallback;
bool m_WasChanged;
bool m_WasRendered;
char m_ClearButtonId;
void UpdateStrData();
enum EMoveDirection
{
FORWARD,
REWIND
};
static void MoveCursor(EMoveDirection Direction, bool MoveWord, const char *pStr, size_t MaxSize, size_t *pCursorPos);
static void SetCompositionWindowPosition(vec2 Anchor, float LineHeight);
void OnActivate();
void OnDeactivate();
public:
static void Init(IClient *pClient, IGraphics *pGraphics, IInput *pInput, ITextRender *pTextRender)
{
ms_pClient = pClient;
ms_pGraphics = pGraphics;
ms_pInput = pInput;
ms_pTextRender = pTextRender;
}
static void RenderCandidates();
static CLineInput *GetActiveInput() { return ms_pActiveInput; }
CLineInput()
{
SetBuffer(nullptr, 0, 0);
}
CLineInput(char *pStr, size_t MaxSize)
{
SetBuffer(pStr, MaxSize);
}
CLineInput(char *pStr, size_t MaxSize, size_t MaxChars)
{
SetBuffer(pStr, MaxSize, MaxChars);
}
void SetBuffer(char *pStr, size_t MaxSize) { SetBuffer(pStr, MaxSize, MaxSize); }
void SetBuffer(char *pStr, size_t MaxSize, size_t MaxChars);
void Clear();
void Set(const char *pString);
void SetRange(const char *pString, size_t Begin, size_t End);
void Insert(const char *pString, size_t Begin);
void Append(const char *pString);
const char *GetString() const { return m_pStr; }
const char *GetDisplayedString();
size_t GetMaxSize() const { return m_MaxSize; }
size_t GetMaxChars() const { return m_MaxChars; }
size_t GetLength() const { return m_Len; }
size_t GetNumChars() const { return m_NumChars; }
bool IsEmpty() const { return GetLength() == 0; }
size_t GetCursorOffset() const { return m_CursorPos; }
void SetCursorOffset(size_t Offset);
size_t GetSelectionStart() const { return m_SelectionStart; }
size_t GetSelectionEnd() const { return m_SelectionEnd; }
size_t GetSelectionLength() const { return m_SelectionEnd - m_SelectionStart; }
bool HasSelection() const { return GetSelectionLength() > 0; }
void SetSelection(size_t Start, size_t End);
void SelectNothing() { SetSelection(GetCursorOffset(), GetCursorOffset()); }
void SelectAll()
{
SetCursorOffset(GetLength());
SetSelection(0, GetLength());
}
size_t OffsetFromActualToDisplay(size_t ActualOffset) const;
size_t OffsetFromDisplayToActual(size_t DisplayOffset) const;
// used either for vertical or horizontal scrolling
float GetScrollOffset() const { return m_ScrollOffset; }
void SetScrollOffset(float ScrollOffset) { m_ScrollOffset = ScrollOffset; }
float GetScrollOffsetChange() const { return m_ScrollOffsetChange; }
void SetScrollOffsetChange(float ScrollOffsetChange) { m_ScrollOffsetChange = ScrollOffsetChange; }
vec2 GetCaretPosition() const { return m_CaretPosition; } // only updated while the input is active
bool IsHidden() const { return m_Hidden; }
void SetHidden(bool Hidden) { m_Hidden = Hidden; }
const char *GetEmptyText() const { return m_pEmptyText; }
void SetEmptyText(const char *pText) { m_pEmptyText = pText; }
void SetClipboardLineCallback(FClipboardLineCallback pfnClipboardLineCallback) { m_pfnClipboardLineCallback = pfnClipboardLineCallback; }
bool ProcessInput(const IInput::CEvent &Event);
bool WasChanged()
{
const bool Changed = m_WasChanged;
m_WasChanged = false;
return Changed;
}
STextBoundingBox Render(const CUIRect *pRect, float FontSize, int Align, bool Changed, float LineWidth);
SMouseSelection *GetMouseSelection() { return &m_MouseSelection; }
const void *GetClearButtonId() const { return &m_ClearButtonId; }
bool IsActive() const { return GetActiveInput() == this; }
void Activate(EInputPriority Priority);
void Deactivate();
};
template
class CLineInputBuffered : public CLineInput
{
char m_aBuffer[MaxSize];
public:
CLineInputBuffered() :
CLineInput()
{
m_aBuffer[0] = '\0';
SetBuffer(m_aBuffer, MaxSize, MaxChars);
}
};
class CLineInputNumber : public CLineInputBuffered<32>
{
public:
CLineInputNumber() :
CLineInputBuffered()
{
}
CLineInputNumber(int Number) :
CLineInputBuffered()
{
SetInteger(Number);
}
CLineInputNumber(float Number) :
CLineInputBuffered()
{
SetFloat(Number);
}
void SetInteger(int Number, int Base = 10);
int GetInteger(int Base = 10) const;
void SetFloat(float Number);
float GetFloat() const;
};
#endif