/* (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; 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() { 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