ddnet/src/game/client/lineinput.h
Robert Müller 71c56f1e70 Ensure line inputs are deactivated when they are not rendered
Check if the active line input was not rendered and deactivate it in that case.

This can happen e.g. when an input in the ingame menu is active and the menu is closed or when switching between menu and editor with an active input.

This was causing the IME candidate list to be rendered ingame after closing the menu. Closes #6666.
2023-05-26 23:58:04 +02:00

229 lines
6 KiB
C++

/* (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 <base/vmath.h>
#include <engine/client.h>
#include <engine/graphics.h>
#include <engine/input.h>
#include <engine/textrender.h>
#include <game/client/ui_rect.h>
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<void(const char *pLine)> 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<size_t MaxSize, size_t MaxChars = MaxSize>
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