From 3bda76ff1fa958bac712b602bde057e5b7aada55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20M=C3=BCller?= Date: Wed, 21 Aug 2024 20:43:53 +0200 Subject: [PATCH] Add touch support to emoticon selector and spectator menu Support using emoticon selector and spectator menu with touch inputs. Touching in the emoticon selector activates the selected (eye) emote and closes the emoticon selector. The spectator menu is kept open when using it for more convenience. The emoticon selector and spectator menu can be closed by touching anywhere outside of them. Additionally, the emoticon selector and specator menu can now be closed by pressing the Escape key (i.e. the back button on Android). This made it necessary to change the order of the components for input handling, so the ingame menu will handle the Escape key after the emoticon selector and spectator menu. This also means that the Escape key can now be used to close the selector/menu when they are stuck open, which was previously delayed until ingame menu or console were opened and closed. --- src/game/client/components/emoticon.cpp | 43 +++++++++++++++++++++-- src/game/client/components/emoticon.h | 8 +++++ src/game/client/components/spectator.cpp | 44 +++++++++++++++++++++--- src/game/client/components/spectator.h | 6 ++++ src/game/client/gameclient.cpp | 2 +- 5 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/game/client/components/emoticon.cpp b/src/game/client/components/emoticon.cpp index 9d0d2b910..dc1fe96b3 100644 --- a/src/game/client/components/emoticon.cpp +++ b/src/game/client/components/emoticon.cpp @@ -41,6 +41,7 @@ void CEmoticon::OnReset() m_Active = false; m_SelectedEmote = -1; m_SelectedEyeEmote = -1; + m_TouchPressedOutside = false; } void CEmoticon::OnRelease() @@ -58,6 +59,16 @@ bool CEmoticon::OnCursorMove(float x, float y, IInput::ECursorType CursorType) return true; } +bool CEmoticon::OnInput(const IInput::CEvent &Event) +{ + if(IsActive() && Event.m_Flags & IInput::FLAG_PRESS && Event.m_Key == KEY_ESCAPE) + { + OnRelease(); + return true; + } + return false; +} + void CEmoticon::OnRender() { if(Client()->State() != IClient::STATE_ONLINE && Client()->State() != IClient::STATE_DEMOPLAYBACK) @@ -65,6 +76,13 @@ void CEmoticon::OnRender() if(!m_Active) { + if(m_TouchPressedOutside) + { + m_SelectedEmote = -1; + m_SelectedEyeEmote = -1; + m_TouchPressedOutside = false; + } + if(m_WasActive && m_SelectedEmote != -1) Emote(m_SelectedEmote); if(m_WasActive && m_SelectedEyeEmote != -1) @@ -82,6 +100,29 @@ void CEmoticon::OnRender() m_WasActive = true; + const CUIRect Screen = *Ui()->Screen(); + + const bool WasTouchPressed = m_TouchState.m_AnyPressed; + Ui()->UpdateTouchState(m_TouchState); + if(m_TouchState.m_AnyPressed) + { + const vec2 TouchPos = (m_TouchState.m_PrimaryPosition - vec2(0.5f, 0.5f)) * Screen.Size(); + const float TouchCenterDistance = length(TouchPos); + if(TouchCenterDistance <= 170.0f) + { + m_SelectorMouse = TouchPos; + } + else if(TouchCenterDistance > 190.0f) + { + m_TouchPressedOutside = true; + } + } + else if(WasTouchPressed) + { + m_Active = false; + return; + } + if(length(m_SelectorMouse) > 170.0f) m_SelectorMouse = normalize(m_SelectorMouse) * 170.0f; @@ -96,8 +137,6 @@ void CEmoticon::OnRender() else if(length(m_SelectorMouse) > 40.0f) m_SelectedEyeEmote = (int)(SelectedAngle / (2 * pi) * NUM_EMOTES); - CUIRect Screen = *Ui()->Screen(); - Ui()->MapScreen(); Graphics()->BlendNormal(); diff --git a/src/game/client/components/emoticon.h b/src/game/client/components/emoticon.h index c7d068cb1..890f1c80e 100644 --- a/src/game/client/components/emoticon.h +++ b/src/game/client/components/emoticon.h @@ -4,7 +4,9 @@ #define GAME_CLIENT_COMPONENTS_EMOTICON_H #include #include + #include +#include class CEmoticon : public CComponent { @@ -15,6 +17,9 @@ class CEmoticon : public CComponent int m_SelectedEmote; int m_SelectedEyeEmote; + CUi::CTouchState m_TouchState; + bool m_TouchPressedOutside; + static void ConKeyEmoticon(IConsole::IResult *pResult, void *pUserData); static void ConEmote(IConsole::IResult *pResult, void *pUserData); @@ -27,9 +32,12 @@ public: virtual void OnRender() override; virtual void OnRelease() override; virtual bool OnCursorMove(float x, float y, IInput::ECursorType CursorType) override; + virtual bool OnInput(const IInput::CEvent &Event) override; void Emote(int Emoticon); void EyeEmote(int EyeEmote); + + bool IsActive() const { return m_Active; } }; #endif diff --git a/src/game/client/components/spectator.cpp b/src/game/client/components/spectator.cpp index 97b9d955b..c14a33f91 100644 --- a/src/game/client/components/spectator.cpp +++ b/src/game/client/components/spectator.cpp @@ -186,6 +186,16 @@ bool CSpectator::OnCursorMove(float x, float y, IInput::ECursorType CursorType) return true; } +bool CSpectator::OnInput(const IInput::CEvent &Event) +{ + if(IsActive() && Event.m_Flags & IInput::FLAG_PRESS && Event.m_Key == KEY_ESCAPE) + { + OnRelease(); + return true; + } + return false; +} + void CSpectator::OnRelease() { OnReset(); @@ -258,8 +268,6 @@ void CSpectator::OnRender() float BoxMove = -10.0f; float BoxOffset = 0.0f; - const bool MousePressed = Input()->KeyPress(KEY_MOUSE_1); - for(const auto &pInfo : m_pClient->m_Snap.m_apInfoByDDTeamName) { if(!pInfo || pInfo->m_Team == TEAM_SPECTATORS) @@ -293,14 +301,42 @@ void CSpectator::OnRender() ObjWidth = 600.0f; } + const vec2 ScreenSize = vec2(Width, Height); + const vec2 ScreenCenter = ScreenSize / 2.0f; + CUIRect SpectatorRect = {Width / 2.0f - ObjWidth, Height / 2.0f - 300.0f, ObjWidth * 2.0f, 600.0f}; + CUIRect SpectatorMouseRect; + SpectatorRect.Margin(20.0f, &SpectatorMouseRect); + + const bool WasTouchPressed = m_TouchState.m_AnyPressed; + Ui()->UpdateTouchState(m_TouchState); + if(m_TouchState.m_AnyPressed) + { + const vec2 TouchPos = (m_TouchState.m_PrimaryPosition - vec2(0.5f, 0.5f)) * ScreenSize; + if(SpectatorMouseRect.Inside(ScreenCenter + TouchPos)) + { + m_SelectorMouse = TouchPos; + } + } + else if(WasTouchPressed) + { + const vec2 TouchPos = (m_TouchState.m_PrimaryPosition - vec2(0.5f, 0.5f)) * ScreenSize; + if(!SpectatorRect.Inside(ScreenCenter + TouchPos)) + { + OnRelease(); + return; + } + } + Graphics()->MapScreen(0, 0, Width, Height); - Graphics()->DrawRect(Width / 2.0f - ObjWidth, Height / 2.0f - 300.0f, ObjWidth * 2, 600.0f, ColorRGBA(0.0f, 0.0f, 0.0f, 0.3f), IGraphics::CORNER_ALL, 20.0f); + SpectatorRect.Draw(ColorRGBA(0.0f, 0.0f, 0.0f, 0.3f), IGraphics::CORNER_ALL, 20.0f); // clamp mouse position to selector area m_SelectorMouse.x = clamp(m_SelectorMouse.x, -(ObjWidth - 20.0f), ObjWidth - 20.0f); m_SelectorMouse.y = clamp(m_SelectorMouse.y, -280.0f, 280.0f); + const bool MousePressed = Input()->KeyPress(KEY_MOUSE_1) || m_TouchState.m_PrimaryPressed; + // draw selections if((Client()->State() == IClient::STATE_DEMOPLAYBACK && m_pClient->m_DemoSpecId == SPEC_FREEVIEW) || (Client()->State() != IClient::STATE_DEMOPLAYBACK && m_pClient->m_Snap.m_SpecInfo.m_SpectatorId == SPEC_FREEVIEW)) @@ -543,7 +579,7 @@ void CSpectator::OnRender() } TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f); - RenderTools()->RenderCursor(m_SelectorMouse + vec2(Width, Height) / 2, 48.0f); + RenderTools()->RenderCursor(ScreenCenter + m_SelectorMouse, 48.0f); } void CSpectator::OnReset() diff --git a/src/game/client/components/spectator.h b/src/game/client/components/spectator.h index e7fdc2449..25dddfb60 100644 --- a/src/game/client/components/spectator.h +++ b/src/game/client/components/spectator.h @@ -6,6 +6,7 @@ #include #include +#include class CSpectator : public CComponent { @@ -21,6 +22,8 @@ class CSpectator : public CComponent int m_SelectedSpectatorId; vec2 m_SelectorMouse; + CUi::CTouchState m_TouchState; + float m_MultiViewActivateDelay; bool CanChangeSpectator(); @@ -39,12 +42,15 @@ public: virtual void OnConsoleInit() override; virtual bool OnCursorMove(float x, float y, IInput::ECursorType CursorType) override; + virtual bool OnInput(const IInput::CEvent &Event) override; virtual void OnRender() override; virtual void OnRelease() override; virtual void OnReset() override; void Spectate(int SpectatorId); void SpectateClosest(); + + bool IsActive() const { return m_Active; } }; #endif diff --git a/src/game/client/gameclient.cpp b/src/game/client/gameclient.cpp index 636f9e806..1f450fa04 100644 --- a/src/game/client/gameclient.cpp +++ b/src/game/client/gameclient.cpp @@ -160,9 +160,9 @@ void CGameClient::OnConsoleInit() &m_GameConsole, &m_Chat, // chat has higher prio, due to that you can quit it by pressing esc &m_Motd, // for pressing esc to remove it - &m_Menus, &m_Spectator, &m_Emoticon, + &m_Menus, &m_Controls, &m_Binds});