@@ -914,131 +914,114 @@ void CMenus::RenderSettingsProfs(CUIRect MainView)
914914
915915void CMenus::RenderCrossChat (CUIRect MainView)
916916{
917+ static bool s_Initialized = false ;
917918 static std::vector<std::string> s_ChatHistory;
918919 static int s_HistoryIndex = -1 ;
919- if (!m_CrossChatInitialized)
920+ static CLineInputBuffered<256 > s_ChatInput;
921+ static int s_LastMsgCount = 0 ; // для автоскролла
922+
923+ if (!s_Initialized)
920924 {
921- m_CrossChatInitialized = true ;
922- m_CrossChatInput .Clear ();
923- m_CrossChatMessages .clear ();
925+ s_Initialized = true ;
926+ s_ChatInput .Clear ();
927+ s_ChatHistory .clear ();
924928
925- char aBuf[64 ];
929+ char aBuf[128 ];
926930 if (GameClient ()->m_WebSocket .m_IsConnected )
927- str_format (aBuf, sizeof (aBuf), " [Server]: Welcome to chat, %s" , g_Config.m_PlayerName );
931+ str_format (aBuf, sizeof (aBuf), " Welcome to chat, %s" , g_Config.m_PlayerName );
928932 else
929- str_format (aBuf, sizeof (aBuf), " [Offline]: Try again later" );
930- GameClient ()->m_WebSocket .m_WebSocketChat .AddMessage (aBuf);
933+ str_copy (aBuf, " Try again later" );
934+
935+ GameClient ()->m_WebSocket .m_WebSocketChat .AddMessage (aBuf, ColorRGBA (0 .0f , 1 .0f , 0 .0f , 1 .0f ), " System: " );
931936 }
932937
933- MainView.Draw (ColorRGBA (0 , 0 , 0 , 0 .5f ), IGraphics::CORNER_ALL, 5 .0f );
938+ MainView.Draw (ColorRGBA (0 , 0 , 0 , 0 .5f ), IGraphics::CORNER_ALL, 5 .f );
934939
935- CUIRect ChatView, InputBar, ReconectRect ;
940+ CUIRect ChatView, InputBar, LeftBar ;
936941 MainView.HSplitBottom (40 .0f , &ChatView, &InputBar);
942+ ChatView.VSplitLeft (ChatView.w / 5 , &LeftBar, &ChatView);
943+
944+ LeftBar.Margin (10 .0f , &LeftBar);
937945 ChatView.Margin (10 .0f , &ChatView);
938- InputBar.VSplitLeft (InputBar.w / 5 , &ReconectRect, &InputBar);
939- InputBar.Margin (10 .0f , &InputBar);
946+ InputBar.Margin (8 .0f , &InputBar);
940947
948+ LeftBar.Draw (ColorRGBA (0 .f , 0 .f , 0 .f , 0 .3f ), IGraphics::CORNER_ALL, 5 .f );
949+ std::lock_guard<std::mutex> lockPlayers (GameClient ()->m_WebSocket .m_WebSocketChat .m_OnlinePlayersMutex );
941950
942- CUIRect LeftBar;
943- ChatView.VSplitLeft (ChatView.w / 5 , &LeftBar, &ChatView);
944- LeftBar.Draw (ColorRGBA (0 , 0 , 0 , 0 .3f ), IGraphics::CORNER_ALL, 5 .0f );
945-
946- CUIRect ChatSettings;
947- ReconectRect.VSplitMid (&ChatSettings, &ReconectRect);
948- ReconectRect.Margin (7 .0f , &ReconectRect);
949- ChatSettings.Margin (7 .0f , &ChatSettings);
950-
951-
952- TextRender ()->SetFontPreset (EFontPreset::ICON_FONT);
953-
954- CButtonContainer SReconnectButton;
955- bool Connected = GameClient ()->m_WebSocket .m_IsConnected ;
956-
957- ColorRGBA ButtonColor = Connected ? ColorRGBA (1 .0f , 0 .0f , 0 .0f , 0 .25f )
958- :
959- ColorRGBA (0 .0f , 1 .0f , 0 .0f , 0 .25f );
960-
961- if (DoButton_Menu (
962- &SReconnectButton,
963- Connected ? FONT_ICON_ARROW_ROTATE_LEFT : FONT_ICON_EXITGAME,
964- 0 ,
965- &ReconectRect,
966- BUTTONFLAG_LEFT,
967- nullptr ,
968- IGraphics::CORNER_ALL,
969- 3 .0f ,
970- 0 .01f ,
971- ButtonColor))
951+ float yOnline = LeftBar.y + 8 .0f ;
952+ for (const auto &player : GameClient ()->m_WebSocket .m_WebSocketChat .m_OnlinePlayers )
972953 {
973- GameClient ()->m_WebSocket .SocketConnect ();
954+ TextRender ()->Text (LeftBar.x + 5 .0f , yOnline, 12 .0f , player.c_str (), -1 );
955+ yOnline += 14 .0f ;
974956 }
975- static bool s_settings_open = false ;
976-
977- CButtonContainer SettingsButton;
978- if (DoButton_Menu (
979- &SettingsButton,
980- FONT_ICON_GEAR,
981- 0 ,
982- &ChatSettings,
983- BUTTONFLAG_ALL,
984- nullptr ,
985- IGraphics::CORNER_ALL,
986- 3 .0f ,
987- 0 .01f ,
988- ColorRGBA (0 .0f , 0 .5f , 1 .0f , 0 .25f )))
957+
958+ static CScrollRegion s_ScrollRegion;
959+ vec2 ScrollOffset (0 .0f , 0 .0f );
960+ CScrollRegionParams ScrollParams;
961+ ScrollParams.m_ScrollUnit = 100 .0f ;
962+
963+ std::vector<CWebSocketChat::SChatMessage> Messages = GameClient ()->m_WebSocket .m_WebSocketChat .GetMessages ();
964+ const bool WasAtEnd = s_ScrollRegion.AtEnd ();
965+ s_ScrollRegion.Begin (&ChatView, &ScrollOffset, &ScrollParams);
966+ ChatView.y += ScrollOffset.y ;
967+
968+ const float MsgHeight = 24 .0f ;
969+ CUIRect Line;
970+ CUIRect LastLine = {};
971+
972+
973+ for (int i = 0 ; i < (int )Messages.size (); i++)
989974 {
990- s_settings_open = !s_settings_open;
991- }
975+ const CWebSocketChat::SChatMessage &Msg = Messages[i];
992976
993- CUIRect SettingsRect;
994- if (s_settings_open)
977+ ChatView.HSplitTop (MsgHeight, &Line, &ChatView);
978+ ChatView.HSplitTop (4 .0f , nullptr , &ChatView);
979+
980+ if (!s_ScrollRegion.AddRect (Line))
981+ continue ;
982+
983+ ColorRGBA BgColor = (Msg.m_Username == g_Config.m_PlayerName )
984+ ? ColorRGBA (0 .0f , 0 .5f , 1 .0f , 0 .15f )
985+ : ColorRGBA (0 .0f , 0 .0f , 0 .0f , 0 .25f );
986+
987+ Line.Draw (BgColor, IGraphics::CORNER_ALL, 4 .0f );
988+
989+ CUIRect TextRect = Line;
990+ TextRect.HMargin (4 .0f , &TextRect);
991+
992+ const float TextFontSize = 12 .5f ;
993+ TextRender ()->TextColor (Msg.m_Color );
994+ Ui ()->DoLabel (&TextRect, (Msg.m_Username + Msg.m_Text ).c_str (), TextFontSize, TEXTALIGN_ML);
995+ TextRender ()->TextColor (TextRender ()->DefaultTextColor ());
996+
997+ LastLine = Line;
998+ }
999+ s_ScrollRegion.End ();
1000+ if (WasAtEnd && (int )Messages.size () > s_LastMsgCount)
9951001 {
996- CUIRect Button;
997- LeftBar.HSplitBottom (LeftBar.h / 3 , &LeftBar, &SettingsRect);
998- SettingsRect.Draw (ColorRGBA (0 .0f , 0 .5f , 1 .0f , 0 .25f ), IGraphics::CORNER_ALL, 3 .0f );
999- TextRender ()->Text (SettingsRect.x + 5 .0f , SettingsRect.y + 5 .0f , 12 .0f , FONT_ICON_GEAR, -1 );
1000- TextRender ()->SetFontPreset (EFontPreset::DEFAULT_FONT);
1001- SettingsRect.VMargin (10 .0f , &SettingsRect);
1002- SettingsRect.HSplitTop (SettingsRect.h / 5 , nullptr , &SettingsRect);
1003-
1004-
1005- SettingsRect.HSplitTop (20 .0f , &Button, &SettingsRect);
1006- if (DoButton_CheckBox (&g_Config.m_ClCrossChatAutoConnect , Localize (" Connect on startup" ), g_Config.m_ClCrossChatAutoConnect , &Button))
1007- g_Config.m_ClCrossChatAutoConnect ^= 1 ;
1002+ s_ScrollRegion.ScrollHere (CScrollRegion::SCROLLHERE_BOTTOM);
10081003 }
10091004
1010- TextRender ()-> SetFontPreset (EFontPreset::DEFAULT_FONT );
1005+ s_LastMsgCount = ( int )Messages. size ( );
10111006
1012- static CLineInputBuffered<64 > s_ChatInput;
1013- s_ChatInput.SetEmptyText (" Send Message" );
1007+ s_ChatInput.SetEmptyText (" Send a message..." );
10141008
10151009 if (Ui ()->ActiveItem () == nullptr )
1016- {
10171010 Ui ()->SetActiveItem (&s_ChatInput);
1018- }
10191011
1020- if (Ui ()->DoEditBox (&s_ChatInput, &InputBar, FontSize + 2 .0f ))
1012+ if (Ui ()->DoEditBox (&s_ChatInput, &InputBar, 14 .0f ))
10211013 {
10221014 Ui ()->SetActiveItem (&s_ChatInput);
1023-
10241015 const char *pText = s_ChatInput.GetString ();
10251016 int64_t Now = time_get ();
10261017
1018+ if (!GameClient ()->m_WebSocket .m_WebSocketChat .m_IsTyping )
1019+ {
1020+ GameClient ()->m_WebSocket .m_WebSocketChat .m_IsTyping = true ;
1021+ GameClient ()->m_WebSocket .m_WebSocketChat .SendTypingState (true );
1022+ }
10271023
1028- if (!GameClient ()->m_WebSocket .m_WebSocketChat .m_IsTyping )
1029- {
1030- GameClient ()->m_WebSocket .m_WebSocketChat .m_IsTyping = true ;
1031- GameClient ()->m_WebSocket .m_WebSocketChat .SendTypingState (true );
1032- }
1033-
1034- GameClient ()->m_WebSocket .m_WebSocketChat .m_LastTypeTime = Now;
1035-
1036- }
1037-
1038- if (GameClient ()->m_WebSocket .m_WebSocketChat .m_IsTyping && time_get () - GameClient ()->m_WebSocket .m_WebSocketChat .m_LastTypeTime > time_freq () * 2 )
1039- {
1040- GameClient ()->m_WebSocket .m_WebSocketChat .m_IsTyping = false ;
1041- GameClient ()->m_WebSocket .m_WebSocketChat .SendTypingState (false );
1024+ GameClient ()->m_WebSocket .m_WebSocketChat .m_LastTypeTime = Now;
10421025 }
10431026
10441027 if (Input ()->KeyPress (KEY_RETURN) || Input ()->KeyPress (KEY_KP_ENTER))
@@ -1047,7 +1030,6 @@ void CMenus::RenderCrossChat(CUIRect MainView)
10471030 if (pText && pText[0 ])
10481031 {
10491032 GameClient ()->m_WebSocket .m_WebSocketChat .SendChatMessage (pText);
1050-
10511033 s_ChatHistory.emplace_back (pText);
10521034 s_HistoryIndex = -1 ;
10531035 s_ChatInput.Clear ();
@@ -1068,7 +1050,6 @@ void CMenus::RenderCrossChat(CUIRect MainView)
10681050 s_HistoryIndex = (int )s_ChatHistory.size () - 1 ;
10691051 else if (s_HistoryIndex > 0 )
10701052 s_HistoryIndex--;
1071-
10721053 s_ChatInput.Set (s_ChatHistory[s_HistoryIndex].c_str ());
10731054 }
10741055 }
@@ -1083,52 +1064,20 @@ void CMenus::RenderCrossChat(CUIRect MainView)
10831064 s_ChatInput.Clear ();
10841065 }
10851066 else
1086- {
10871067 s_ChatInput.Set (s_ChatHistory[s_HistoryIndex].c_str ());
1088- }
10891068 }
10901069 }
10911070
1092- std::lock_guard<std::mutex> lock (GameClient ()->m_WebSocket .m_WebSocketChat .m_OnlinePlayersMutex );
1093- float yOnline = LeftBar.y + 10 .0f ;
1094- for (const auto &player : GameClient ()->m_WebSocket .m_WebSocketChat .m_OnlinePlayers )
1095- {
1096- TextRender ()->Text (LeftBar.x + 5 .0f , yOnline, 12 .0f , player.c_str (), -1 );
1097- yOnline += 15 .0f ;
1098- }
1099-
1100- std::vector<CWebSocketChat::SChatMessage> Messages = GameClient ()->m_WebSocket .m_WebSocketChat .GetMessages ();
1101- const float LineHeight = 14 .0f ;
1102- float y = ChatView.y + ChatView.h - LineHeight;
1103-
1104- for (auto it = Messages.rbegin (); it != Messages.rend (); ++it)
11051071 {
1106- std::stringstream ss (it->m_Text );
1107- std::string line;
1108- while (std::getline (ss, line, ' \n ' ))
1109- {
1110- TextRender ()->TextColor (it->m_Color );
1111- TextRender ()->Text (ChatView.x + 10 , y, 12 .0f , line.c_str (), -1 );
1112- TextRender ()->TextColor (TextRender ()->DefaultTextColor ());
1113- y -= 14 .0f ;
1114- if (y < ChatView.y )
1115- break ;
1116- }
1117- if (y < ChatView.y )
1118- break ;
1119- }
1072+ std::lock_guard<std::mutex> lockTyping (GameClient ()->m_WebSocket .m_WebSocketChat .m_TypingMutex );
11201073
1121- {
1122- std::lock_guard<std::mutex> lock (GameClient ()->m_WebSocket .m_WebSocketChat .m_TypingMutex );
11231074 if (!GameClient ()->m_WebSocket .m_WebSocketChat .m_TypingUsers .empty ())
11241075 {
11251076 std::string TypingText;
11261077 size_t Count = GameClient ()->m_WebSocket .m_WebSocketChat .m_TypingUsers .size ();
11271078
11281079 if (Count == 1 )
1129- {
11301080 TypingText = *GameClient ()->m_WebSocket .m_WebSocketChat .m_TypingUsers .begin () + " is typing..." ;
1131- }
11321081 else if (Count == 2 )
11331082 {
11341083 auto it = GameClient ()->m_WebSocket .m_WebSocketChat .m_TypingUsers .begin ();
@@ -1137,15 +1086,20 @@ void CMenus::RenderCrossChat(CUIRect MainView)
11371086 TypingText = first + " and " + second + " are typing..." ;
11381087 }
11391088 else
1140- {
1141- TypingText = " A lot of people are typing..." ;
1142- }
1089+ TypingText = " Several people are typing..." ;
11431090
11441091 TextRender ()->TextColor (ColorRGBA (0 .8f , 0 .8f , 0 .8f , 1 .0f ));
11451092 TextRender ()->Text (ChatView.x + 10 , InputBar.y - 15 .0f , 11 .0f , TypingText.c_str (), -1 );
11461093 TextRender ()->TextColor (TextRender ()->DefaultTextColor ());
11471094 }
11481095 }
1096+
1097+ if (GameClient ()->m_WebSocket .m_WebSocketChat .m_IsTyping &&
1098+ time_get () - GameClient ()->m_WebSocket .m_WebSocketChat .m_LastTypeTime > time_freq () * 2 )
1099+ {
1100+ GameClient ()->m_WebSocket .m_WebSocketChat .m_IsTyping = false ;
1101+ GameClient ()->m_WebSocket .m_WebSocketChat .SendTypingState (false );
1102+ }
11491103}
11501104
11511105// TODO: Add everything to here
0 commit comments