2010-11-20 10:37:14 +00:00
/* (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. */
2022-05-23 18:16:18 +00:00
# include <base/log.h>
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
# include <engine/engine.h>
2022-05-23 18:16:18 +00:00
# include <engine/favorites.h>
2011-03-23 12:06:35 +00:00
# include <engine/friends.h>
2011-03-18 16:59:48 +00:00
# include <engine/keys.h>
2010-05-29 07:25:38 +00:00
# include <engine/serverbrowser.h>
2020-09-26 19:41:58 +00:00
# include <engine/shared/config.h>
2022-12-09 15:15:19 +00:00
# include <engine/shared/localization.h>
2010-05-29 07:25:38 +00:00
# include <engine/textrender.h>
2023-01-07 08:20:25 +00:00
# include <game/client/animstate.h>
2020-09-26 19:41:58 +00:00
# include <game/client/components/countryflags.h>
2023-01-05 11:21:10 +00:00
# include <game/client/gameclient.h>
2011-03-18 16:59:48 +00:00
# include <game/client/render.h>
# include <game/client/ui.h>
2023-01-05 11:21:10 +00:00
# include <game/client/ui_listbox.h>
2020-09-26 19:41:58 +00:00
# include <game/localization.h>
2011-03-18 16:59:48 +00:00
# include "menus.h"
2023-04-03 23:40:54 +00:00
using namespace FontIcons ;
2023-08-22 18:45:37 +00:00
static const ColorRGBA gs_HighlightedTextColor = ColorRGBA ( 0.4f , 0.4f , 1.0f , 1.0f ) ;
template < size_t N >
static void FormatServerbrowserPing ( char ( & aBuffer ) [ N ] , const CServerInfo * pInfo )
2018-07-11 20:46:04 +00:00
{
if ( ! pInfo - > m_LatencyIsEstimated )
{
2023-08-22 18:45:37 +00:00
str_from_int ( pInfo - > m_Latency , aBuffer ) ;
2018-07-11 20:46:04 +00:00
return ;
}
static const char * LOCATION_NAMES [ CServerInfo : : NUM_LOCS ] = {
" " , // LOC_UNKNOWN
2022-12-09 15:15:19 +00:00
Localizable ( " AFR " ) , // LOC_AFRICA
Localizable ( " ASI " ) , // LOC_ASIA
Localizable ( " AUS " ) , // LOC_AUSTRALIA
Localizable ( " EUR " ) , // LOC_EUROPE
Localizable ( " NA " ) , // LOC_NORTH_AMERICA
Localizable ( " SA " ) , // LOC_SOUTH_AMERICA
Localizable ( " CHN " ) , // LOC_CHINA
2018-07-11 20:46:04 +00:00
} ;
dbg_assert ( 0 < = pInfo - > m_Location & & pInfo - > m_Location < CServerInfo : : NUM_LOCS , " location out of range " ) ;
2023-08-22 18:45:37 +00:00
str_copy ( aBuffer , Localize ( LOCATION_NAMES [ pInfo - > m_Location ] ) ) ;
2018-07-11 20:46:04 +00:00
}
2023-08-22 18:45:37 +00:00
static ColorRGBA GetPingTextColor ( int Latency )
2010-05-29 07:25:38 +00:00
{
2023-08-22 18:45:37 +00:00
return color_cast < ColorRGBA > ( ColorHSLA ( ( 300.0f - clamp ( Latency , 0 , 300 ) ) / 1000.0f , 1.0f , 0.5f ) ) ;
}
2008-08-27 15:48:50 +00:00
2023-08-22 18:45:37 +00:00
static ColorRGBA GetGametypeTextColor ( const char * pGametype )
{
ColorHSLA HslaColor ;
if ( str_comp ( pGametype , " DM " ) = = 0 | | str_comp ( pGametype , " TDM " ) = = 0 | | str_comp ( pGametype , " CTF " ) = = 0 )
HslaColor = ColorHSLA ( 0.33f , 1.0f , 0.75f ) ;
else if ( str_find_nocase ( pGametype , " catch " ) )
HslaColor = ColorHSLA ( 0.17f , 1.0f , 0.75f ) ;
else if ( str_find_nocase ( pGametype , " idm " ) | | str_find_nocase ( pGametype , " itdm " ) | | str_find_nocase ( pGametype , " ictf " ) | | str_find_nocase ( pGametype , " f-ddrace " ) )
HslaColor = ColorHSLA ( 0.0f , 1.0f , 0.75f ) ;
else if ( str_find_nocase ( pGametype , " fng " ) )
HslaColor = ColorHSLA ( 0.83f , 1.0f , 0.75f ) ;
else if ( str_find_nocase ( pGametype , " gores " ) )
HslaColor = ColorHSLA ( 0.525f , 1.0f , 0.75f ) ;
else if ( str_find_nocase ( pGametype , " BW " ) )
HslaColor = ColorHSLA ( 0.05f , 1.0f , 0.75f ) ;
else if ( str_find_nocase ( pGametype , " ddracenet " ) | | str_find_nocase ( pGametype , " ddnet " ) | | str_find_nocase ( pGametype , " 0xf " ) )
HslaColor = ColorHSLA ( 0.58f , 1.0f , 0.75f ) ;
else if ( str_find_nocase ( pGametype , " ddrace " ) | | str_find_nocase ( pGametype , " mkrace " ) )
HslaColor = ColorHSLA ( 0.75f , 1.0f , 0.75f ) ;
else if ( str_find_nocase ( pGametype , " race " ) | | str_find_nocase ( pGametype , " fastcap " ) )
HslaColor = ColorHSLA ( 0.46f , 1.0f , 0.75f ) ;
else if ( str_find_nocase ( pGametype , " s-ddr " ) )
HslaColor = ColorHSLA ( 1.0f , 1.0f , 0.7f ) ;
else
HslaColor = ColorHSLA ( 1.0f , 1.0f , 1.0f ) ;
return color_cast < ColorRGBA > ( HslaColor ) ;
}
void CMenus : : RenderServerbrowserServerList ( CUIRect View , bool & WasListboxItemActivated )
{
static CListBox s_ListBox ;
2008-08-27 15:48:50 +00:00
2023-08-22 18:45:37 +00:00
CUIRect Headers ;
View . HSplitTop ( ms_ListheaderHeight , & Headers , & View ) ;
Headers . Draw ( ColorRGBA ( 1.0f , 1.0f , 1.0f , 0.25f ) , IGraphics : : CORNER_T , 5.0f ) ;
Headers . VSplitRight ( s_ListBox . ScrollbarWidthMax ( ) , & Headers , nullptr ) ;
View . Draw ( ColorRGBA ( 0.0f , 0.0f , 0.0f , 0.15f ) , IGraphics : : CORNER_NONE , 0.0f ) ;
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
struct SColumn
2008-08-27 15:48:50 +00:00
{
2011-02-12 10:40:36 +00:00
int m_ID ;
2010-05-29 07:25:38 +00:00
int m_Sort ;
2023-08-30 15:49:28 +00:00
const char * m_pCaption ;
2010-05-29 07:25:38 +00:00
int m_Direction ;
float m_Width ;
CUIRect m_Rect ;
2008-08-27 15:48:50 +00:00
} ;
2010-05-29 07:25:38 +00:00
2008-08-27 15:48:50 +00:00
enum
{
2020-09-26 19:41:58 +00:00
COL_FLAG_LOCK = 0 ,
2008-09-03 20:03:01 +00:00
COL_FLAG_FAV ,
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
COL_COMMUNITY ,
2008-08-27 15:48:50 +00:00
COL_NAME ,
COL_GAMETYPE ,
COL_MAP ,
COL_PLAYERS ,
COL_PING ,
2023-08-22 18:45:37 +00:00
UI_ELEM_LOCK_ICON = 0 ,
UI_ELEM_FAVORITE_ICON ,
UI_ELEM_NAME_1 ,
UI_ELEM_NAME_2 ,
UI_ELEM_NAME_3 ,
UI_ELEM_GAMETYPE ,
UI_ELEM_MAP_1 ,
UI_ELEM_MAP_2 ,
UI_ELEM_MAP_3 ,
UI_ELEM_FINISH_ICON ,
UI_ELEM_PLAYERS ,
UI_ELEM_FRIEND_ICON ,
UI_ELEM_PING ,
NUM_UI_ELEMS ,
2008-08-27 15:48:50 +00:00
} ;
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
static SColumn s_aCols [ ] = {
{ - 1 , - 1 , " " , - 1 , 2.0f , { 0 } } ,
{ COL_FLAG_LOCK , - 1 , " " , - 1 , 14.0f , { 0 } } ,
{ COL_FLAG_FAV , - 1 , " " , - 1 , 14.0f , { 0 } } ,
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
{ COL_COMMUNITY , - 1 , " " , - 1 , 28.0f , { 0 } } ,
2023-08-22 18:45:37 +00:00
{ COL_NAME , IServerBrowser : : SORT_NAME , Localizable ( " Name " ) , 0 , 50.0f , { 0 } } ,
{ COL_GAMETYPE , IServerBrowser : : SORT_GAMETYPE , Localizable ( " Type " ) , 1 , 50.0f , { 0 } } ,
{ COL_MAP , IServerBrowser : : SORT_MAP , Localizable ( " Map " ) , 1 , 120.0f + ( Headers . w - 480 ) / 8 , { 0 } } ,
{ COL_PLAYERS , IServerBrowser : : SORT_NUMPLAYERS , Localizable ( " Players " ) , 1 , 85.0f , { 0 } } ,
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
{ - 1 , - 1 , " " , 1 , 4.0f , { 0 } } ,
2023-08-22 18:45:37 +00:00
{ COL_PING , IServerBrowser : : SORT_PING , Localizable ( " Ping " ) , 1 , 40.0f , { 0 } } ,
2008-08-27 15:48:50 +00:00
} ;
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
const int NumCols = std : : size ( s_aCols ) ;
2010-05-29 07:25:38 +00:00
2008-08-27 15:48:50 +00:00
// do layout
2010-05-29 07:25:38 +00:00
for ( int i = 0 ; i < NumCols ; i + + )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
if ( s_aCols [ i ] . m_Direction = = - 1 )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
Headers . VSplitLeft ( s_aCols [ i ] . m_Width , & s_aCols [ i ] . m_Rect , & Headers ) ;
2020-09-26 19:41:58 +00:00
if ( i + 1 < NumCols )
2008-08-27 15:48:50 +00:00
{
2023-08-22 18:45:37 +00:00
Headers . VSplitLeft ( 2.0f , nullptr , & Headers ) ;
2008-08-27 15:48:50 +00:00
}
}
}
2010-05-29 07:25:38 +00:00
2020-09-26 19:41:58 +00:00
for ( int i = NumCols - 1 ; i > = 0 ; i - - )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
if ( s_aCols [ i ] . m_Direction = = 1 )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
Headers . VSplitRight ( s_aCols [ i ] . m_Width , & Headers , & s_aCols [ i ] . m_Rect ) ;
2023-08-22 18:45:37 +00:00
Headers . VSplitRight ( 2.0f , & Headers , nullptr ) ;
2008-08-27 15:48:50 +00:00
}
}
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
for ( auto & Col : s_aCols )
2008-08-27 15:48:50 +00:00
{
2023-08-22 18:45:37 +00:00
if ( Col . m_Direction = = 0 )
Col . m_Rect = Headers ;
2008-08-27 15:48:50 +00:00
}
2010-05-29 07:25:38 +00:00
2020-08-24 21:23:37 +00:00
const bool PlayersOrPing = ( g_Config . m_BrSort = = IServerBrowser : : SORT_NUMPLAYERS | | g_Config . m_BrSort = = IServerBrowser : : SORT_PING ) ;
2008-08-27 15:48:50 +00:00
// do headers
2023-08-22 18:45:37 +00:00
for ( const auto & Col : s_aCols )
2008-08-27 15:48:50 +00:00
{
2023-08-22 18:45:37 +00:00
int Checked = g_Config . m_BrSort = = Col . m_Sort ;
if ( PlayersOrPing & & g_Config . m_BrSortOrder = = 2 & & ( Col . m_Sort = = IServerBrowser : : SORT_NUMPLAYERS | | Col . m_Sort = = IServerBrowser : : SORT_PING ) )
2020-08-24 21:23:37 +00:00
Checked = 2 ;
2023-08-22 18:45:37 +00:00
if ( DoButton_GridHeader ( & Col . m_ID , Localize ( Col . m_pCaption ) , Checked , & Col . m_Rect ) )
2008-08-27 15:48:50 +00:00
{
2023-08-22 18:45:37 +00:00
if ( Col . m_Sort ! = - 1 )
2008-08-27 15:48:50 +00:00
{
2023-08-22 18:45:37 +00:00
if ( g_Config . m_BrSort = = Col . m_Sort )
g_Config . m_BrSortOrder = ( g_Config . m_BrSortOrder + 1 ) % ( PlayersOrPing ? 3 : 2 ) ;
2008-08-27 15:48:50 +00:00
else
2010-05-29 07:25:38 +00:00
g_Config . m_BrSortOrder = 0 ;
2023-08-22 18:45:37 +00:00
g_Config . m_BrSort = Col . m_Sort ;
2008-08-27 15:48:50 +00:00
}
}
}
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
const int NumServers = ServerBrowser ( ) - > NumSortedServers ( ) ;
2010-05-29 07:25:38 +00:00
2009-01-21 20:39:48 +00:00
// display important messages in the middle of the screen so no
// users misses it
{
2021-07-08 17:18:01 +00:00
if ( ! ServerBrowser ( ) - > NumServers ( ) & & ServerBrowser ( ) - > IsGettingServerlist ( ) )
2023-08-22 18:45:37 +00:00
UI ( ) - > DoLabel ( & View , Localize ( " Getting server list from master server " ) , 16.0f , TEXTALIGN_MC ) ;
2010-05-29 07:25:38 +00:00
else if ( ! ServerBrowser ( ) - > NumServers ( ) )
2023-08-22 18:45:37 +00:00
UI ( ) - > DoLabel ( & View , Localize ( " No servers found " ) , 16.0f , TEXTALIGN_MC ) ;
2010-05-29 07:25:38 +00:00
else if ( ServerBrowser ( ) - > NumServers ( ) & & ! NumServers )
2023-08-22 18:45:37 +00:00
UI ( ) - > DoLabel ( & View , Localize ( " No servers match your filter criteria " ) , 16.0f , TEXTALIGN_MC ) ;
2009-01-21 20:39:48 +00:00
}
2008-09-07 21:13:24 +00:00
2023-06-07 16:08:55 +00:00
s_ListBox . SetActive ( ! UI ( ) - > IsPopupOpen ( ) ) ;
s_ListBox . DoStart ( ms_ListheaderHeight , NumServers , 1 , 3 , - 1 , & View , false ) ;
2010-05-29 07:25:38 +00:00
2023-07-15 08:43:33 +00:00
if ( m_ServerBrowserShouldRevealSelection )
2023-01-05 11:21:10 +00:00
{
s_ListBox . ScrollToSelected ( ) ;
2023-07-15 08:43:33 +00:00
m_ServerBrowserShouldRevealSelection = false ;
2023-01-05 11:21:10 +00:00
}
2010-05-29 07:25:38 +00:00
m_SelectedIndex = - 1 ;
2023-08-22 18:45:37 +00:00
const auto & & RenderBrowserIcons = [ this ] ( CUIElement : : SUIElementRect & UIRect , CUIRect * pRect , const ColorRGBA & TextColor , const ColorRGBA & TextOutlineColor , const char * pText , int TextAlign , bool SmallFont = false ) {
const float FontSize = SmallFont ? 6.0f : 14.0f ;
2023-07-17 13:49:41 +00:00
TextRender ( ) - > SetFontPreset ( EFontPreset : : ICON_FONT ) ;
2022-03-19 10:25:54 +00:00
TextRender ( ) - > SetRenderFlags ( ETextRenderFlags : : TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_OVERSIZE ) ;
TextRender ( ) - > TextColor ( TextColor ) ;
TextRender ( ) - > TextOutlineColor ( TextOutlineColor ) ;
2023-06-14 17:26:10 +00:00
UI ( ) - > DoLabelStreamed ( UIRect , pRect , pText , FontSize , TextAlign ) ;
2022-03-19 10:25:54 +00:00
TextRender ( ) - > TextOutlineColor ( TextRender ( ) - > DefaultTextOutlineColor ( ) ) ;
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
TextRender ( ) - > SetRenderFlags ( 0 ) ;
2023-07-17 13:49:41 +00:00
TextRender ( ) - > SetFontPreset ( EFontPreset : : DEFAULT_FONT ) ;
2022-03-19 10:25:54 +00:00
} ;
2023-09-20 14:57:36 +00:00
std : : vector < CUIElement * > & vpServerBrowserUiElements = m_avpServerBrowserUiElements [ ServerBrowser ( ) - > GetCurrentType ( ) ] ;
if ( vpServerBrowserUiElements . size ( ) < ( size_t ) NumServers )
vpServerBrowserUiElements . resize ( NumServers , nullptr ) ;
2023-09-17 19:10:01 +00:00
2018-03-13 20:59:07 +00:00
for ( int i = 0 ; i < NumServers ; i + + )
2008-08-27 15:48:50 +00:00
{
2023-01-05 11:21:10 +00:00
const CServerInfo * pItem = ServerBrowser ( ) - > SortedGet ( i ) ;
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
const CCommunity * pCommunity = ServerBrowser ( ) - > Community ( pItem - > m_aCommunityId ) ;
2010-05-29 07:25:38 +00:00
2023-09-20 14:57:36 +00:00
if ( vpServerBrowserUiElements [ i ] = = nullptr )
2020-10-12 10:29:47 +00:00
{
2023-09-20 14:57:36 +00:00
vpServerBrowserUiElements [ i ] = UI ( ) - > GetNewUIElement ( NUM_UI_ELEMS ) ;
2020-10-12 10:29:47 +00:00
}
2023-09-20 14:57:36 +00:00
CUIElement * pUiElement = vpServerBrowserUiElements [ i ] ;
2020-10-12 10:29:47 +00:00
2023-06-07 16:08:55 +00:00
const CListboxItem ListItem = s_ListBox . DoNextItem ( pItem , str_comp ( pItem - > m_aAddress , g_Config . m_UiServerAddress ) = = 0 ) ;
2023-01-05 11:21:10 +00:00
if ( ListItem . m_Selected )
2010-05-29 07:25:38 +00:00
m_SelectedIndex = i ;
2008-08-27 15:48:50 +00:00
2023-01-05 11:21:10 +00:00
if ( ! ListItem . m_Visible )
2010-05-29 07:25:38 +00:00
{
// reset active item, if not visible
2022-05-27 08:55:32 +00:00
if ( UI ( ) - > CheckActiveItem ( pItem ) )
2022-05-27 09:59:14 +00:00
UI ( ) - > SetActiveItem ( nullptr ) ;
2008-08-27 15:48:50 +00:00
2010-05-29 07:25:38 +00:00
// don't render invisible items
continue ;
}
2023-06-14 17:26:10 +00:00
const float FontSize = 12.0f ;
2023-08-22 18:45:37 +00:00
char aTemp [ 64 ] ;
for ( const auto & Col : s_aCols )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
CUIRect Button ;
2023-08-22 18:45:37 +00:00
Button . x = Col . m_Rect . x ;
2023-01-05 11:21:10 +00:00
Button . y = ListItem . m_Rect . y ;
Button . h = ListItem . m_Rect . h ;
2023-08-22 18:45:37 +00:00
Button . w = Col . m_Rect . w ;
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
const int ID = Col . m_ID ;
2011-02-12 10:40:36 +00:00
if ( ID = = COL_FLAG_LOCK )
2008-08-27 15:48:50 +00:00
{
2010-05-29 07:25:38 +00:00
if ( pItem - > m_Flags & SERVER_FLAG_PASSWORD )
2022-03-19 10:25:54 +00:00
{
2023-09-17 19:10:01 +00:00
RenderBrowserIcons ( * pUiElement - > Rect ( UI_ELEM_LOCK_ICON ) , & Button , ColorRGBA ( 0.75f , 0.75f , 0.75f , 1.0f ) , TextRender ( ) - > DefaultTextOutlineColor ( ) , FONT_ICON_LOCK , TEXTALIGN_MC ) ;
2022-03-19 10:25:54 +00:00
}
2008-10-05 09:57:46 +00:00
}
2011-02-12 10:40:36 +00:00
else if ( ID = = COL_FLAG_FAV )
2008-09-03 20:03:01 +00:00
{
2022-05-23 18:16:18 +00:00
if ( pItem - > m_Favorite ! = TRISTATE : : NONE )
2022-03-19 10:25:54 +00:00
{
2023-09-17 19:10:01 +00:00
RenderBrowserIcons ( * pUiElement - > Rect ( UI_ELEM_FAVORITE_ICON ) , & Button , ColorRGBA ( 0.94f , 0.4f , 0.4f , 1.0f ) , TextRender ( ) - > DefaultTextOutlineColor ( ) , FONT_ICON_HEART , TEXTALIGN_MC ) ;
2022-03-19 10:25:54 +00:00
}
2008-08-27 15:48:50 +00:00
}
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
else if ( ID = = COL_COMMUNITY )
2019-03-19 06:46:48 +00:00
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
if ( pCommunity ! = nullptr )
2022-03-19 10:25:54 +00:00
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
const SCommunityIcon * pIcon = FindCommunityIcon ( pCommunity - > Id ( ) ) ;
if ( pIcon ! = nullptr )
{
CUIRect CommunityIcon ;
Button . Margin ( 2.0f , & CommunityIcon ) ;
RenderCommunityIcon ( pIcon , CommunityIcon , true ) ;
UI ( ) - > DoButtonLogic ( & pItem - > m_aCommunityId , 0 , & CommunityIcon ) ;
GameClient ( ) - > m_Tooltips . DoToolTip ( & pItem - > m_aCommunityId , & CommunityIcon , pCommunity - > Name ( ) ) ;
}
2022-03-19 10:25:54 +00:00
}
2019-03-19 06:46:48 +00:00
}
2011-02-12 10:40:36 +00:00
else if ( ID = = COL_NAME )
2008-08-27 15:48:50 +00:00
{
2023-06-14 17:26:10 +00:00
SLabelProperties Props ;
Props . m_MaxWidth = Button . w ;
Props . m_StopAtEnd = true ;
Props . m_EnableWidthCheck = false ;
2022-09-25 12:37:24 +00:00
bool Printed = false ;
2020-09-26 19:41:58 +00:00
if ( g_Config . m_BrFilterString [ 0 ] & & ( pItem - > m_QuickSearchHit & IServerBrowser : : QUICK_SERVERNAME ) )
2023-08-22 18:45:37 +00:00
Printed = PrintHighlighted ( pItem - > m_aName , [ & ] ( const char * pFilteredStr , const int FilterLen ) {
2023-09-17 19:10:01 +00:00
UI ( ) - > DoLabelStreamed ( * pUiElement - > Rect ( UI_ELEM_NAME_1 ) , & Button , pItem - > m_aName , FontSize , TEXTALIGN_ML , Props , ( int ) ( pFilteredStr - pItem - > m_aName ) ) ;
2023-08-22 18:45:37 +00:00
TextRender ( ) - > TextColor ( gs_HighlightedTextColor ) ;
2023-09-17 19:10:01 +00:00
UI ( ) - > DoLabelStreamed ( * pUiElement - > Rect ( UI_ELEM_NAME_2 ) , & Button , pFilteredStr , FontSize , TEXTALIGN_ML , Props , FilterLen , & pUiElement - > Rect ( UI_ELEM_NAME_1 ) - > m_Cursor ) ;
2023-08-22 18:45:37 +00:00
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
2023-09-17 19:10:01 +00:00
UI ( ) - > DoLabelStreamed ( * pUiElement - > Rect ( UI_ELEM_NAME_3 ) , & Button , pFilteredStr + FilterLen , FontSize , TEXTALIGN_ML , Props , - 1 , & pUiElement - > Rect ( UI_ELEM_NAME_2 ) - > m_Cursor ) ;
2022-12-23 22:23:44 +00:00
} ) ;
2022-09-25 12:37:24 +00:00
if ( ! Printed )
2023-09-17 19:10:01 +00:00
UI ( ) - > DoLabelStreamed ( * pUiElement - > Rect ( UI_ELEM_NAME_1 ) , & Button , pItem - > m_aName , FontSize , TEXTALIGN_ML , Props ) ;
2023-08-22 18:45:37 +00:00
}
else if ( ID = = COL_GAMETYPE )
{
SLabelProperties Props ;
Props . m_MaxWidth = Button . w ;
Props . m_StopAtEnd = true ;
Props . m_EnableWidthCheck = false ;
if ( g_Config . m_UiColorizeGametype )
{
TextRender ( ) - > TextColor ( GetGametypeTextColor ( pItem - > m_aGameType ) ) ;
}
2023-09-17 19:10:01 +00:00
UI ( ) - > DoLabelStreamed ( * pUiElement - > Rect ( UI_ELEM_GAMETYPE ) , & Button , pItem - > m_aGameType , FontSize , TEXTALIGN_ML , Props ) ;
2023-08-22 18:45:37 +00:00
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
2008-08-27 15:48:50 +00:00
}
2011-02-12 10:40:36 +00:00
else if ( ID = = COL_MAP )
2010-06-09 22:40:22 +00:00
{
2017-08-30 19:34:01 +00:00
{
CUIRect Icon ;
Button . VMargin ( 4.0f , & Button ) ;
Button . VSplitLeft ( Button . h , & Icon , & Button ) ;
2023-09-30 10:39:30 +00:00
if ( g_Config . m_BrIndicateFinished & & pItem - > m_HasRank = = CServerInfo : : RANK_RANKED )
2022-03-19 10:25:54 +00:00
{
2023-08-22 18:45:37 +00:00
Icon . Margin ( 2.0f , & Icon ) ;
2023-09-17 19:10:01 +00:00
RenderBrowserIcons ( * pUiElement - > Rect ( UI_ELEM_FINISH_ICON ) , & Icon , TextRender ( ) - > DefaultTextColor ( ) , TextRender ( ) - > DefaultTextOutlineColor ( ) , FONT_ICON_FLAG_CHECKERED , TEXTALIGN_MC ) ;
2022-03-19 10:25:54 +00:00
}
2017-08-30 19:34:01 +00:00
}
2023-06-14 17:26:10 +00:00
SLabelProperties Props ;
Props . m_MaxWidth = Button . w ;
Props . m_StopAtEnd = true ;
Props . m_EnableWidthCheck = false ;
2022-09-25 12:37:24 +00:00
bool Printed = false ;
2020-09-26 19:41:58 +00:00
if ( g_Config . m_BrFilterString [ 0 ] & & ( pItem - > m_QuickSearchHit & IServerBrowser : : QUICK_MAPNAME ) )
2023-08-22 18:45:37 +00:00
Printed = PrintHighlighted ( pItem - > m_aMap , [ & ] ( const char * pFilteredStr , const int FilterLen ) {
2023-09-17 19:10:01 +00:00
UI ( ) - > DoLabelStreamed ( * pUiElement - > Rect ( UI_ELEM_MAP_1 ) , & Button , pItem - > m_aMap , FontSize , TEXTALIGN_ML , Props , ( int ) ( pFilteredStr - pItem - > m_aMap ) ) ;
2023-08-22 18:45:37 +00:00
TextRender ( ) - > TextColor ( gs_HighlightedTextColor ) ;
2023-09-17 19:10:01 +00:00
UI ( ) - > DoLabelStreamed ( * pUiElement - > Rect ( UI_ELEM_MAP_2 ) , & Button , pFilteredStr , FontSize , TEXTALIGN_ML , Props , FilterLen , & pUiElement - > Rect ( UI_ELEM_MAP_1 ) - > m_Cursor ) ;
2023-08-22 18:45:37 +00:00
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
2023-09-17 19:10:01 +00:00
UI ( ) - > DoLabelStreamed ( * pUiElement - > Rect ( UI_ELEM_MAP_3 ) , & Button , pFilteredStr + FilterLen , FontSize , TEXTALIGN_ML , Props , - 1 , & pUiElement - > Rect ( UI_ELEM_MAP_2 ) - > m_Cursor ) ;
2022-12-23 22:23:44 +00:00
} ) ;
2022-09-25 12:37:24 +00:00
if ( ! Printed )
2023-09-17 19:10:01 +00:00
UI ( ) - > DoLabelStreamed ( * pUiElement - > Rect ( UI_ELEM_MAP_1 ) , & Button , pItem - > m_aMap , FontSize , TEXTALIGN_ML , Props ) ;
2010-06-09 22:40:22 +00:00
}
2011-02-12 10:40:36 +00:00
else if ( ID = = COL_PLAYERS )
2008-08-27 15:48:50 +00:00
{
2022-11-20 07:37:14 +00:00
Button . VMargin ( 2.0f , & Button ) ;
2011-06-26 15:10:13 +00:00
if ( pItem - > m_FriendState ! = IFriends : : FRIEND_NO )
{
2023-08-22 18:45:37 +00:00
CUIRect Icon ;
2022-11-20 19:26:53 +00:00
Button . VSplitRight ( 50.0f , & Icon , & Button ) ;
2011-06-26 15:10:13 +00:00
Icon . Margin ( 2.0f , & Icon ) ;
2023-09-17 19:10:01 +00:00
RenderBrowserIcons ( * pUiElement - > Rect ( UI_ELEM_FRIEND_ICON ) , & Icon , ColorRGBA ( 0.94f , 0.4f , 0.4f , 1.0f ) , TextRender ( ) - > DefaultTextOutlineColor ( ) , FONT_ICON_HEART , TEXTALIGN_MC ) ;
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
2023-09-30 10:57:10 +00:00
if ( pItem - > m_FriendNum > 1 )
2022-11-20 07:37:14 +00:00
{
2023-09-30 10:57:10 +00:00
str_from_int ( pItem - > m_FriendNum , aTemp ) ;
2023-08-22 18:45:37 +00:00
TextRender ( ) - > TextColor ( 0.94f , 0.8f , 0.8f , 1.0f ) ;
UI ( ) - > DoLabel ( & Icon , aTemp , 9.0f , TEXTALIGN_MC ) ;
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
2022-11-20 07:37:14 +00:00
}
2011-06-26 15:10:13 +00:00
}
2018-10-29 21:03:57 +00:00
str_format ( aTemp , sizeof ( aTemp ) , " %i/%i " , pItem - > m_NumFilteredPlayers , ServerBrowser ( ) - > Max ( * pItem ) ) ;
2020-09-26 19:41:58 +00:00
if ( g_Config . m_BrFilterString [ 0 ] & & ( pItem - > m_QuickSearchHit & IServerBrowser : : QUICK_PLAYER ) )
2023-08-22 18:45:37 +00:00
{
TextRender ( ) - > TextColor ( gs_HighlightedTextColor ) ;
}
2023-09-17 19:10:01 +00:00
UI ( ) - > DoLabelStreamed ( * pUiElement - > Rect ( UI_ELEM_PLAYERS ) , & Button , aTemp , FontSize , TEXTALIGN_MR ) ;
2023-08-22 18:45:37 +00:00
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
2008-08-27 15:48:50 +00:00
}
2011-02-12 10:40:36 +00:00
else if ( ID = = COL_PING )
2008-08-27 15:48:50 +00:00
{
2021-12-28 00:05:50 +00:00
Button . VMargin ( 4.0f , & Button ) ;
2023-08-22 18:45:37 +00:00
FormatServerbrowserPing ( aTemp , pItem ) ;
2018-03-13 20:59:07 +00:00
if ( g_Config . m_UiColorizePing )
2014-05-03 15:24:34 +00:00
{
2023-08-22 18:45:37 +00:00
TextRender ( ) - > TextColor ( GetPingTextColor ( pItem - > m_Latency ) ) ;
2014-05-03 15:24:34 +00:00
}
2023-09-17 19:10:01 +00:00
UI ( ) - > DoLabelStreamed ( * pUiElement - > Rect ( UI_ELEM_PING ) , & Button , aTemp , FontSize , TEXTALIGN_MR ) ;
2023-08-22 18:45:37 +00:00
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
2014-05-03 15:24:34 +00:00
}
2008-08-27 15:48:50 +00:00
}
}
2023-01-05 11:21:10 +00:00
const int NewSelected = s_ListBox . DoEnd ( ) ;
if ( NewSelected ! = m_SelectedIndex )
2008-08-27 15:48:50 +00:00
{
2023-01-05 11:21:10 +00:00
m_SelectedIndex = NewSelected ;
if ( m_SelectedIndex > = 0 )
2020-11-05 19:19:29 +00:00
{
2023-01-05 11:21:10 +00:00
// select the new server
const CServerInfo * pItem = ServerBrowser ( ) - > SortedGet ( NewSelected ) ;
if ( pItem )
2021-06-26 11:39:14 +00:00
{
2023-01-05 11:21:10 +00:00
str_copy ( g_Config . m_UiServerAddress , pItem - > m_aAddress ) ;
2023-07-15 08:43:33 +00:00
m_ServerBrowserShouldRevealSelection = true ;
2021-06-26 11:39:14 +00:00
}
2020-11-05 19:19:29 +00:00
}
2008-08-27 15:48:50 +00:00
}
2023-08-22 18:45:37 +00:00
WasListboxItemActivated = s_ListBox . WasItemActivated ( ) ;
}
void CMenus : : RenderServerbrowserStatusBox ( CUIRect StatusBox , bool WasListboxItemActivated )
{
2022-12-18 22:21:35 +00:00
// Render bar that shows the loading progression.
// The bar is only shown while loading and fades out when it's done.
CUIRect RefreshBar ;
2023-08-22 18:45:37 +00:00
StatusBox . HSplitTop ( 5.0f , & RefreshBar , & StatusBox ) ;
2022-12-18 22:21:35 +00:00
static float s_LoadingProgressionFadeEnd = 0.0f ;
if ( ServerBrowser ( ) - > IsRefreshing ( ) & & ServerBrowser ( ) - > LoadingProgression ( ) < 100 )
{
s_LoadingProgressionFadeEnd = Client ( ) - > GlobalTime ( ) + 2.0f ;
}
const float LoadingProgressionTimeDiff = s_LoadingProgressionFadeEnd - Client ( ) - > GlobalTime ( ) ;
if ( LoadingProgressionTimeDiff > 0.0f )
{
const float RefreshBarAlpha = minimum ( LoadingProgressionTimeDiff , 0.8f ) ;
RefreshBar . h = 2.0f ;
RefreshBar . w * = ServerBrowser ( ) - > LoadingProgression ( ) / 100.0f ;
RefreshBar . Draw ( ColorRGBA ( 1.0f , 1.0f , 1.0f , RefreshBarAlpha ) , IGraphics : : CORNER_NONE , 0.0f ) ;
}
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
TextRender ( ) - > SetFontPreset ( EFontPreset : : ICON_FONT ) ;
TextRender ( ) - > SetRenderFlags ( ETextRenderFlags : : TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_OVERSIZE ) ;
const float SearchExcludeAddrStrMax = 130.0f ;
const float SearchIconWidth = TextRender ( ) - > TextWidth ( 16.0f , FONT_ICON_MAGNIFYING_GLASS ) ;
const float ExcludeIconWidth = TextRender ( ) - > TextWidth ( 16.0f , FONT_ICON_BAN ) ;
const float ExcludeSearchIconMax = maximum ( SearchIconWidth , ExcludeIconWidth ) ;
TextRender ( ) - > SetRenderFlags ( 0 ) ;
TextRender ( ) - > SetFontPreset ( EFontPreset : : DEFAULT_FONT ) ;
CUIRect SearchInfoAndAddr , ServersAndConnect , ServersPlayersOnline , SearchAndInfo , ServerAddr , ConnectButtons ;
StatusBox . VSplitRight ( 135.0f , & SearchInfoAndAddr , & ServersAndConnect ) ;
2020-09-19 20:03:21 +00:00
if ( SearchInfoAndAddr . w > 350.0f )
2023-08-22 18:45:37 +00:00
SearchInfoAndAddr . VSplitLeft ( 350.0f , & SearchInfoAndAddr , nullptr ) ;
2020-09-19 20:03:21 +00:00
SearchInfoAndAddr . HSplitTop ( 40.0f , & SearchAndInfo , & ServerAddr ) ;
2023-08-22 18:45:37 +00:00
ServersAndConnect . HSplitTop ( 35.0f , & ServersPlayersOnline , & ConnectButtons ) ;
2023-06-30 13:52:24 +00:00
ConnectButtons . HSplitTop ( 5.0f , nullptr , & ConnectButtons ) ;
2020-09-16 01:30:03 +00:00
2023-08-22 18:45:37 +00:00
CUIRect QuickSearch , QuickExclude ;
SearchAndInfo . HSplitTop ( 20.0f , & QuickSearch , & QuickExclude ) ;
QuickSearch . Margin ( 2.0f , & QuickSearch ) ;
QuickExclude . Margin ( 2.0f , & QuickExclude ) ;
2020-09-16 01:30:03 +00:00
2009-01-21 18:09:06 +00:00
// render quick search
2014-12-10 03:49:16 +00:00
{
2023-07-17 13:49:41 +00:00
TextRender ( ) - > SetFontPreset ( EFontPreset : : ICON_FONT ) ;
2020-10-06 10:25:10 +00:00
TextRender ( ) - > SetRenderFlags ( ETextRenderFlags : : TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_OVERSIZE ) ;
2023-04-09 19:24:06 +00:00
UI ( ) - > DoLabel ( & QuickSearch , FONT_ICON_MAGNIFYING_GLASS , 16.0f , TEXTALIGN_ML ) ;
2018-03-13 20:59:07 +00:00
TextRender ( ) - > SetRenderFlags ( 0 ) ;
2023-07-17 13:49:41 +00:00
TextRender ( ) - > SetFontPreset ( EFontPreset : : DEFAULT_FONT ) ;
2023-08-22 18:45:37 +00:00
QuickSearch . VSplitLeft ( ExcludeSearchIconMax , nullptr , & QuickSearch ) ;
QuickSearch . VSplitLeft ( 5.0f , nullptr , & QuickSearch ) ;
2020-09-16 01:30:03 +00:00
2020-10-06 15:55:22 +00:00
char aBufSearch [ 64 ] ;
str_format ( aBufSearch , sizeof ( aBufSearch ) , " %s: " , Localize ( " Search " ) ) ;
2023-04-09 19:24:06 +00:00
UI ( ) - > DoLabel ( & QuickSearch , aBufSearch , 14.0f , TEXTALIGN_ML ) ;
2023-08-22 18:45:37 +00:00
QuickSearch . VSplitLeft ( SearchExcludeAddrStrMax , nullptr , & QuickSearch ) ;
QuickSearch . VSplitLeft ( 5.0f , nullptr , & QuickSearch ) ;
2020-09-16 01:30:03 +00:00
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
static CLineInput s_FilterInput ( g_Config . m_BrFilterString , sizeof ( g_Config . m_BrFilterString ) ) ;
2023-08-31 19:16:51 +00:00
if ( ! UI ( ) - > IsPopupOpen ( ) & & Input ( ) - > KeyPress ( KEY_F ) & & Input ( ) - > ModifierIsPressed ( ) )
2022-03-13 18:09:33 +00:00
{
2023-04-28 15:17:05 +00:00
UI ( ) - > SetActiveItem ( & s_FilterInput ) ;
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
s_FilterInput . SelectAll ( ) ;
2022-03-13 18:09:33 +00:00
}
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if ( UI ( ) - > DoClearableEditBox ( & s_FilterInput , & QuickSearch , 12.0f ) )
2011-03-18 18:03:13 +00:00
Client ( ) - > ServerBrowserUpdate ( ) ;
2010-05-29 07:25:38 +00:00
}
2011-04-13 18:37:12 +00:00
2014-12-10 03:49:16 +00:00
// render quick exclude
2014-01-14 19:58:47 +00:00
{
2023-07-17 13:49:41 +00:00
TextRender ( ) - > SetFontPreset ( EFontPreset : : ICON_FONT ) ;
2020-10-06 10:25:10 +00:00
TextRender ( ) - > SetRenderFlags ( ETextRenderFlags : : TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_OVERSIZE ) ;
2023-04-09 19:24:06 +00:00
UI ( ) - > DoLabel ( & QuickExclude , FONT_ICON_BAN , 16.0f , TEXTALIGN_ML ) ;
2018-03-13 20:59:07 +00:00
TextRender ( ) - > SetRenderFlags ( 0 ) ;
2023-07-17 13:49:41 +00:00
TextRender ( ) - > SetFontPreset ( EFontPreset : : DEFAULT_FONT ) ;
2023-08-22 18:45:37 +00:00
QuickExclude . VSplitLeft ( ExcludeSearchIconMax , nullptr , & QuickExclude ) ;
QuickExclude . VSplitLeft ( 5.0f , nullptr , & QuickExclude ) ;
2020-09-16 01:30:03 +00:00
2020-10-06 15:55:22 +00:00
char aBufExclude [ 64 ] ;
str_format ( aBufExclude , sizeof ( aBufExclude ) , " %s: " , Localize ( " Exclude " ) ) ;
2023-04-09 19:24:06 +00:00
UI ( ) - > DoLabel ( & QuickExclude , aBufExclude , 14.0f , TEXTALIGN_ML ) ;
2023-08-22 18:45:37 +00:00
QuickExclude . VSplitLeft ( SearchExcludeAddrStrMax , nullptr , & QuickExclude ) ;
QuickExclude . VSplitLeft ( 5.0f , nullptr , & QuickExclude ) ;
2020-09-16 01:30:03 +00:00
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
static CLineInput s_ExcludeInput ( g_Config . m_BrExcludeString , sizeof ( g_Config . m_BrExcludeString ) ) ;
2023-08-31 19:16:51 +00:00
if ( ! UI ( ) - > IsPopupOpen ( ) & & Input ( ) - > KeyPress ( KEY_X ) & & Input ( ) - > ShiftIsPressed ( ) & & Input ( ) - > ModifierIsPressed ( ) )
2023-08-22 18:45:37 +00:00
{
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
UI ( ) - > SetActiveItem ( & s_ExcludeInput ) ;
2023-08-22 18:45:37 +00:00
s_ExcludeInput . SelectAll ( ) ;
}
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if ( UI ( ) - > DoClearableEditBox ( & s_ExcludeInput , & QuickExclude , 12.0f ) )
2014-12-10 03:49:16 +00:00
Client ( ) - > ServerBrowserUpdate ( ) ;
2014-01-14 19:58:47 +00:00
}
2014-12-10 03:49:16 +00:00
// render status
2023-08-22 18:45:37 +00:00
{
CUIRect ServersOnline , PlayersOnline ;
ServersPlayersOnline . HSplitMid ( & PlayersOnline , & ServersOnline ) ;
char aBuf [ 128 ] ;
if ( ServerBrowser ( ) - > NumServers ( ) ! = 1 )
str_format ( aBuf , sizeof ( aBuf ) , Localize ( " %d of %d servers " ) , ServerBrowser ( ) - > NumSortedServers ( ) , ServerBrowser ( ) - > NumServers ( ) ) ;
else
str_format ( aBuf , sizeof ( aBuf ) , Localize ( " %d of %d server " ) , ServerBrowser ( ) - > NumSortedServers ( ) , ServerBrowser ( ) - > NumServers ( ) ) ;
UI ( ) - > DoLabel ( & ServersOnline , aBuf , 12.0f , TEXTALIGN_MR ) ;
2023-10-01 18:17:55 +00:00
if ( ServerBrowser ( ) - > NumSortedPlayers ( ) ! = 1 )
str_format ( aBuf , sizeof ( aBuf ) , Localize ( " %d players " ) , ServerBrowser ( ) - > NumSortedPlayers ( ) ) ;
2023-08-22 18:45:37 +00:00
else
2023-10-01 18:17:55 +00:00
str_format ( aBuf , sizeof ( aBuf ) , Localize ( " %d player " ) , ServerBrowser ( ) - > NumSortedPlayers ( ) ) ;
2023-08-22 18:45:37 +00:00
UI ( ) - > DoLabel ( & PlayersOnline , aBuf , 12.0f , TEXTALIGN_MR ) ;
}
2020-09-16 01:30:03 +00:00
2023-08-22 18:45:37 +00:00
// address info
2020-09-16 01:30:03 +00:00
{
2023-08-22 18:45:37 +00:00
CUIRect ServerAddrLabel , ServerAddrEditBox ;
2020-09-16 01:30:03 +00:00
ServerAddr . Margin ( 2.0f , & ServerAddr ) ;
2023-08-22 18:45:37 +00:00
ServerAddr . VSplitLeft ( SearchExcludeAddrStrMax + 5.0f + ExcludeSearchIconMax + 5.0f , & ServerAddrLabel , & ServerAddrEditBox ) ;
2020-09-16 01:30:03 +00:00
2023-08-22 18:45:37 +00:00
UI ( ) - > DoLabel ( & ServerAddrLabel , Localize ( " Server address: " ) , 14.0f , TEXTALIGN_ML ) ;
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
static CLineInput s_ServerAddressInput ( g_Config . m_UiServerAddress , sizeof ( g_Config . m_UiServerAddress ) ) ;
2023-08-22 18:45:37 +00:00
if ( UI ( ) - > DoClearableEditBox ( & s_ServerAddressInput , & ServerAddrEditBox , 12.0f ) )
2023-07-15 08:43:33 +00:00
m_ServerBrowserShouldRevealSelection = true ;
2023-08-22 18:45:37 +00:00
}
2020-09-16 01:30:03 +00:00
2023-08-22 18:45:37 +00:00
// buttons
{
2023-05-27 16:22:50 +00:00
CUIRect ButtonRefresh , ButtonConnect ;
2023-06-30 13:52:24 +00:00
ConnectButtons . VSplitMid ( & ButtonRefresh , & ButtonConnect , 5.0f ) ;
2020-09-16 01:30:03 +00:00
2023-05-27 16:22:50 +00:00
// refresh button
{
char aLabelBuf [ 32 ] = { 0 } ;
2023-08-22 18:45:37 +00:00
const auto & & RefreshLabelFunc = [ this , aLabelBuf ] ( ) mutable {
2023-05-27 16:22:50 +00:00
if ( ServerBrowser ( ) - > IsRefreshing ( ) | | ServerBrowser ( ) - > IsGettingServerlist ( ) )
str_format ( aLabelBuf , sizeof ( aLabelBuf ) , " %s%s " , FONT_ICON_ARROW_ROTATE_RIGHT , FONT_ICON_ELLIPSIS ) ;
else
str_copy ( aLabelBuf , FONT_ICON_ARROW_ROTATE_RIGHT ) ;
return aLabelBuf ;
} ;
2020-09-16 01:30:03 +00:00
2023-05-27 16:22:50 +00:00
SMenuButtonProperties Props ;
Props . m_HintRequiresStringCheck = true ;
Props . m_UseIconFont = true ;
2020-09-16 01:30:03 +00:00
2023-05-27 16:22:50 +00:00
static CButtonContainer s_RefreshButton ;
2023-08-31 19:16:51 +00:00
if ( UI ( ) - > DoButton_Menu ( m_RefreshButton , & s_RefreshButton , RefreshLabelFunc , & ButtonRefresh , Props ) | | ( ! UI ( ) - > IsPopupOpen ( ) & & ( Input ( ) - > KeyPress ( KEY_F5 ) | | ( Input ( ) - > KeyPress ( KEY_R ) & & Input ( ) - > ModifierIsPressed ( ) ) ) ) )
2023-05-27 16:22:50 +00:00
{
RefreshBrowserTab ( g_Config . m_UiPage ) ;
}
2020-09-16 01:30:03 +00:00
}
2023-05-27 16:22:50 +00:00
// connect button
2020-09-16 01:30:03 +00:00
{
2023-08-22 18:45:37 +00:00
const auto & & ConnectLabelFunc = [ ] ( ) { return FONT_ICON_RIGHT_TO_BRACKET ; } ;
2023-05-27 16:22:50 +00:00
SMenuButtonProperties Props ;
Props . m_UseIconFont = true ;
Props . m_Color = ColorRGBA ( 0.5f , 1.0f , 0.5f , 0.5f ) ;
static CButtonContainer s_ConnectButton ;
2023-08-22 18:45:37 +00:00
if ( UI ( ) - > DoButton_Menu ( m_ConnectButton , & s_ConnectButton , ConnectLabelFunc , & ButtonConnect , Props ) | | WasListboxItemActivated | | ( ! UI ( ) - > IsPopupOpen ( ) & & UI ( ) - > ConsumeHotkey ( CUI : : HOTKEY_ENTER ) ) )
2023-05-27 16:22:50 +00:00
{
Connect ( g_Config . m_UiServerAddress ) ;
}
2020-09-16 01:30:03 +00:00
}
}
2008-09-04 18:42:26 +00:00
}
2023-05-19 18:31:59 +00:00
void CMenus : : Connect ( const char * pAddress )
2022-11-30 22:41:32 +00:00
{
2023-05-19 15:08:51 +00:00
if ( Client ( ) - > State ( ) = = IClient : : STATE_ONLINE & & Client ( ) - > GetCurrentRaceTime ( ) / 60 > = g_Config . m_ClConfirmDisconnectTime & & g_Config . m_ClConfirmDisconnectTime > = 0 )
2022-11-30 22:41:32 +00:00
{
str_copy ( m_aNextServer , pAddress ) ;
PopupConfirm ( Localize ( " Disconnect " ) , Localize ( " Are you sure that you want to disconnect and switch to a different server? " ) , Localize ( " Yes " ) , Localize ( " No " ) , & CMenus : : PopupConfirmSwitchServer ) ;
}
else
Client ( ) - > Connect ( pAddress ) ;
}
void CMenus : : PopupConfirmSwitchServer ( )
{
Client ( ) - > Connect ( m_aNextServer ) ;
}
2010-05-29 07:25:38 +00:00
void CMenus : : RenderServerbrowserFilters ( CUIRect View )
2008-09-04 18:42:26 +00:00
{
2023-08-22 18:45:37 +00:00
const float RowHeight = 18.0f ;
const float FontSize = ( RowHeight - 4.0f ) * CUI : : ms_FontmodHeight ; // based on DoButton_CheckBox
2020-09-16 01:30:03 +00:00
2023-08-22 18:45:37 +00:00
View . Draw ( ColorRGBA ( 0.0f , 0.0f , 0.0f , 0.15f ) , IGraphics : : CORNER_B , 4.0f ) ;
View . Margin ( 5.0f , & View ) ;
2008-09-04 18:42:26 +00:00
2023-08-22 18:45:37 +00:00
CUIRect Button , ResetButton ;
View . HSplitBottom ( RowHeight , & View , & ResetButton ) ;
View . HSplitBottom ( 3.0f , & View , nullptr ) ;
2008-09-04 18:42:26 +00:00
2023-08-22 18:45:37 +00:00
View . HSplitTop ( RowHeight , & Button , & View ) ;
2018-03-13 20:59:07 +00:00
if ( DoButton_CheckBox ( & g_Config . m_BrFilterEmpty , Localize ( " Has people playing " ) , g_Config . m_BrFilterEmpty , & Button ) )
2010-05-29 07:25:38 +00:00
g_Config . m_BrFilterEmpty ^ = 1 ;
2008-09-04 18:42:26 +00:00
2023-08-22 18:45:37 +00:00
View . HSplitTop ( RowHeight , & Button , & View ) ;
2011-03-20 14:33:49 +00:00
if ( DoButton_CheckBox ( & g_Config . m_BrFilterSpectators , Localize ( " Count players only " ) , g_Config . m_BrFilterSpectators , & Button ) )
g_Config . m_BrFilterSpectators ^ = 1 ;
2023-08-22 18:45:37 +00:00
View . HSplitTop ( RowHeight , & Button , & View ) ;
2018-03-13 20:59:07 +00:00
if ( DoButton_CheckBox ( & g_Config . m_BrFilterFull , Localize ( " Server not full " ) , g_Config . m_BrFilterFull , & Button ) )
2010-05-29 07:25:38 +00:00
g_Config . m_BrFilterFull ^ = 1 ;
2008-09-04 18:42:26 +00:00
2023-08-22 18:45:37 +00:00
View . HSplitTop ( RowHeight , & Button , & View ) ;
2018-03-13 20:59:07 +00:00
if ( DoButton_CheckBox ( & g_Config . m_BrFilterFriends , Localize ( " Show friends only " ) , g_Config . m_BrFilterFriends , & Button ) )
2011-03-23 12:06:35 +00:00
g_Config . m_BrFilterFriends ^ = 1 ;
2023-08-22 18:45:37 +00:00
View . HSplitTop ( RowHeight , & Button , & View ) ;
2018-03-13 20:59:07 +00:00
if ( DoButton_CheckBox ( & g_Config . m_BrFilterPw , Localize ( " No password " ) , g_Config . m_BrFilterPw , & Button ) )
2010-05-29 07:25:38 +00:00
g_Config . m_BrFilterPw ^ = 1 ;
2008-09-04 18:42:26 +00:00
2023-08-22 18:45:37 +00:00
View . HSplitTop ( RowHeight , & Button , & View ) ;
2018-03-13 20:59:07 +00:00
if ( DoButton_CheckBox ( & g_Config . m_BrFilterGametypeStrict , Localize ( " Strict gametype filter " ) , g_Config . m_BrFilterGametypeStrict , & Button ) )
2011-04-17 09:57:33 +00:00
g_Config . m_BrFilterGametypeStrict ^ = 1 ;
2011-04-13 18:37:12 +00:00
2023-08-22 18:45:37 +00:00
View . HSplitTop ( 3.0f , nullptr , & View ) ;
View . HSplitTop ( RowHeight , & Button , & View ) ;
2023-04-09 19:24:06 +00:00
UI ( ) - > DoLabel ( & Button , Localize ( " Game types: " ) , FontSize , TEXTALIGN_ML ) ;
2023-08-22 18:45:37 +00:00
Button . VSplitRight ( 60.0f , nullptr , & Button ) ;
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
static CLineInput s_GametypeInput ( g_Config . m_BrFilterGametype , sizeof ( g_Config . m_BrFilterGametype ) ) ;
if ( UI ( ) - > DoEditBox ( & s_GametypeInput , & Button , FontSize ) )
2011-03-18 18:03:13 +00:00
Client ( ) - > ServerBrowserUpdate ( ) ;
2008-09-04 18:42:26 +00:00
2011-03-18 18:03:13 +00:00
// server address
2023-08-22 18:45:37 +00:00
View . HSplitTop ( 6.0f , nullptr , & View ) ;
View . HSplitTop ( RowHeight , & Button , & View ) ;
View . HSplitTop ( 6.0f , nullptr , & View ) ;
2023-04-09 19:24:06 +00:00
UI ( ) - > DoLabel ( & Button , Localize ( " Server address: " ) , FontSize , TEXTALIGN_ML ) ;
2023-08-22 18:45:37 +00:00
Button . VSplitRight ( 60.0f , nullptr , & Button ) ;
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
static CLineInput s_FilterServerAddressInput ( g_Config . m_BrFilterServerAddress , sizeof ( g_Config . m_BrFilterServerAddress ) ) ;
if ( UI ( ) - > DoEditBox ( & s_FilterServerAddressInput , & Button , FontSize ) )
2011-03-18 18:03:13 +00:00
Client ( ) - > ServerBrowserUpdate ( ) ;
2011-06-29 20:27:32 +00:00
// player country
{
2023-08-22 18:45:37 +00:00
CUIRect Flag ;
View . HSplitTop ( RowHeight , & Button , & View ) ;
Button . VSplitRight ( 60.0f , & Button , & Flag ) ;
2011-06-29 20:27:32 +00:00
if ( DoButton_CheckBox ( & g_Config . m_BrFilterCountry , Localize ( " Player country: " ) , g_Config . m_BrFilterCountry , & Button ) )
g_Config . m_BrFilterCountry ^ = 1 ;
2011-08-11 08:59:14 +00:00
2023-08-22 18:45:37 +00:00
const float OldWidth = Flag . w ;
Flag . w = Flag . h * 2.0f ;
Flag . x + = ( OldWidth - Flag . w ) / 2.0f ;
m_pClient - > m_CountryFlags . Render ( g_Config . m_BrFilterCountryIndex , ColorRGBA ( 1.0f , 1.0f , 1.0f , UI ( ) - > HotItem ( ) = = & g_Config . m_BrFilterCountryIndex ? 1.0f : g_Config . m_BrFilterCountry ? 0.9f : 0.5f ) , Flag . x , Flag . y , Flag . w , Flag . h ) ;
2011-06-29 20:27:32 +00:00
2023-08-22 18:45:37 +00:00
if ( UI ( ) - > DoButtonLogic ( & g_Config . m_BrFilterCountryIndex , 0 , & Flag ) )
2023-05-21 19:17:08 +00:00
{
static SPopupMenuId s_PopupCountryId ;
static SPopupCountrySelectionContext s_PopupCountryContext ;
s_PopupCountryContext . m_pMenus = this ;
s_PopupCountryContext . m_Selection = g_Config . m_BrFilterCountryIndex ;
s_PopupCountryContext . m_New = true ;
2023-08-22 18:45:37 +00:00
UI ( ) - > DoPopupMenu ( & s_PopupCountryId , Flag . x , Flag . y + Flag . h , 490 , 210 , & s_PopupCountryContext , PopupCountrySelection ) ;
2023-05-21 19:17:08 +00:00
}
2011-06-29 20:27:32 +00:00
}
2023-08-22 18:45:37 +00:00
View . HSplitTop ( RowHeight , & Button , & View ) ;
2018-08-21 07:03:29 +00:00
if ( DoButton_CheckBox ( & g_Config . m_BrFilterConnectingPlayers , Localize ( " Filter connecting players " ) , g_Config . m_BrFilterConnectingPlayers , & Button ) )
g_Config . m_BrFilterConnectingPlayers ^ = 1 ;
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
// community filter
if ( ( g_Config . m_UiPage = = PAGE_INTERNET | | g_Config . m_UiPage = = PAGE_FAVORITES ) & & ! ServerBrowser ( ) - > Communities ( ) . empty ( ) )
{
ServerBrowser ( ) - > CleanFilters ( ) ;
CUIRect Row ;
View . HSplitTop ( 6.0f , nullptr , & View ) ;
View . HSplitTop ( 19.0f , & Row , & View ) ;
Row . Draw ( ColorRGBA ( 0.0f , 0.0f , 0.0f , 0.3f ) , IGraphics : : CORNER_T , 4.0f ) ;
UI ( ) - > DoLabel ( & Row , Localize ( " Communities " ) , 12.0f , TEXTALIGN_MC ) ;
View . HSplitTop ( 4.0f * 17.0f + CScrollRegion : : HEIGHT_MAGIC_FIX , & Row , & View ) ;
View . HSplitTop ( 3.0f , nullptr , & View ) ;
Row . Draw ( ColorRGBA ( 0.0f , 0.0f , 0.0f , 0.15f ) , IGraphics : : CORNER_B , 4.0f ) ;
RenderServerbrowserCommunitiesFilter ( Row ) ;
}
// map finish filters
if ( m_CommunityCache . m_AnyRanksAvailable )
2014-09-19 21:52:09 +00:00
{
2023-08-22 18:45:37 +00:00
View . HSplitTop ( RowHeight , & Button , & View ) ;
2018-03-13 20:59:07 +00:00
if ( DoButton_CheckBox ( & g_Config . m_BrIndicateFinished , Localize ( " Indicate map finish " ) , g_Config . m_BrIndicateFinished , & Button ) )
2020-08-26 17:23:25 +00:00
{
2017-09-07 18:51:46 +00:00
g_Config . m_BrIndicateFinished ^ = 1 ;
2020-09-26 19:41:58 +00:00
if ( g_Config . m_BrIndicateFinished )
2020-08-26 17:23:25 +00:00
ServerBrowser ( ) - > Refresh ( ServerBrowser ( ) - > GetCurrentType ( ) ) ;
}
2017-09-07 18:51:46 +00:00
if ( g_Config . m_BrIndicateFinished )
{
2023-08-22 18:45:37 +00:00
View . HSplitTop ( RowHeight , & Button , & View ) ;
2018-03-13 20:59:07 +00:00
if ( DoButton_CheckBox ( & g_Config . m_BrFilterUnfinishedMap , Localize ( " Unfinished map " ) , g_Config . m_BrFilterUnfinishedMap , & Button ) )
2017-09-07 18:51:46 +00:00
g_Config . m_BrFilterUnfinishedMap ^ = 1 ;
}
else
{
g_Config . m_BrFilterUnfinishedMap = 0 ;
}
2019-03-24 22:15:38 +00:00
}
2017-08-30 19:34:01 +00:00
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
if ( ! m_CommunityCache . m_vpSelectableCountries . empty ( ) | | ! m_CommunityCache . m_vpSelectableTypes . empty ( ) )
2019-03-24 22:15:38 +00:00
{
2023-08-22 18:45:37 +00:00
const ColorRGBA ColorActive = ColorRGBA ( 0.0f , 0.0f , 0.0f , 0.3f ) ;
const ColorRGBA ColorInactive = ColorRGBA ( 0.0f , 0.0f , 0.0f , 0.15f ) ;
2014-09-19 21:52:09 +00:00
2023-08-22 18:45:37 +00:00
CUIRect TabContents , CountriesTab , TypesTab ;
View . HSplitTop ( 6.0f , nullptr , & View ) ;
View . HSplitTop ( 19.0f , & Button , & View ) ;
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
View . HSplitTop ( minimum ( 4.0f * 22.0f + CScrollRegion : : HEIGHT_MAGIC_FIX , View . h ) , & TabContents , & View ) ;
2023-08-22 18:45:37 +00:00
Button . VSplitMid ( & CountriesTab , & TypesTab ) ;
2023-09-20 15:51:55 +00:00
TabContents . Draw ( ColorActive , IGraphics : : CORNER_B , 4.0f ) ;
2014-09-19 21:52:09 +00:00
2023-08-22 18:45:37 +00:00
enum EFilterTab
{
FILTERTAB_COUNTRIES = 0 ,
FILTERTAB_TYPES ,
} ;
static EFilterTab s_ActiveTab = FILTERTAB_COUNTRIES ;
2014-09-19 21:52:09 +00:00
2022-07-16 13:32:06 +00:00
static CButtonContainer s_CountriesButton ;
2023-08-22 18:45:37 +00:00
if ( DoButton_MenuTab ( & s_CountriesButton , Localize ( " Countries " ) , s_ActiveTab = = FILTERTAB_COUNTRIES , & CountriesTab , IGraphics : : CORNER_TL , nullptr , & ColorInactive , & ColorActive , nullptr , 4.0f ) )
2014-12-14 15:45:18 +00:00
{
2023-08-22 18:45:37 +00:00
s_ActiveTab = FILTERTAB_COUNTRIES ;
2014-12-14 15:45:18 +00:00
}
2014-09-19 21:52:09 +00:00
2022-07-16 13:32:06 +00:00
static CButtonContainer s_TypesButton ;
2023-08-22 18:45:37 +00:00
if ( DoButton_MenuTab ( & s_TypesButton , Localize ( " Types " ) , s_ActiveTab = = FILTERTAB_TYPES , & TypesTab , IGraphics : : CORNER_TR , nullptr , & ColorInactive , & ColorActive , nullptr , 4.0f ) )
2014-09-19 21:52:09 +00:00
{
2023-08-22 18:45:37 +00:00
s_ActiveTab = FILTERTAB_TYPES ;
2014-12-14 15:45:18 +00:00
}
2014-11-21 13:11:04 +00:00
2023-08-22 18:45:37 +00:00
if ( s_ActiveTab = = FILTERTAB_COUNTRIES )
2014-12-14 15:45:18 +00:00
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
RenderServerbrowserCountriesFilter ( TabContents ) ;
2023-08-22 18:45:37 +00:00
}
else if ( s_ActiveTab = = FILTERTAB_TYPES )
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
RenderServerbrowserTypesFilter ( TabContents ) ;
2023-08-22 18:45:37 +00:00
}
}
2014-09-19 21:52:09 +00:00
2023-08-22 18:45:37 +00:00
static CButtonContainer s_ResetButton ;
if ( DoButton_Menu ( & s_ResetButton , Localize ( " Reset filter " ) , 0 , & ResetButton ) )
{
g_Config . m_BrFilterString [ 0 ] = ' \0 ' ;
g_Config . m_BrExcludeString [ 0 ] = ' \0 ' ;
g_Config . m_BrFilterFull = 0 ;
g_Config . m_BrFilterEmpty = 0 ;
g_Config . m_BrFilterSpectators = 0 ;
g_Config . m_BrFilterFriends = 0 ;
g_Config . m_BrFilterCountry = 0 ;
g_Config . m_BrFilterCountryIndex = - 1 ;
g_Config . m_BrFilterPw = 0 ;
g_Config . m_BrFilterGametype [ 0 ] = ' \0 ' ;
g_Config . m_BrFilterGametypeStrict = 0 ;
g_Config . m_BrFilterConnectingPlayers = 1 ;
g_Config . m_BrFilterUnfinishedMap = 0 ;
g_Config . m_BrFilterServerAddress [ 0 ] = ' \0 ' ;
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
ConfigManager ( ) - > Reset ( " br_filter_exclude_communities " ) ;
ConfigManager ( ) - > Reset ( " br_filter_exclude_countries " ) ;
ConfigManager ( ) - > Reset ( " br_filter_exclude_types " ) ;
Client ( ) - > ServerBrowserUpdate ( ) ;
UpdateCommunityCache ( true ) ;
2023-08-22 18:45:37 +00:00
}
}
2014-09-19 21:52:09 +00:00
2023-08-22 18:45:37 +00:00
void CMenus : : RenderServerbrowserDDNetFilter ( CUIRect View ,
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
IFilterList & Filter ,
2023-08-22 18:45:37 +00:00
float ItemHeight , int MaxItems , int ItemsPerRow ,
CScrollRegion & ScrollRegion , std : : vector < unsigned char > & vItemIds ,
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
bool UpdateCommunityCacheOnChange ,
2023-08-22 18:45:37 +00:00
const std : : function < const char * ( int ItemIndex ) > & GetItemName ,
const std : : function < void ( int ItemIndex , CUIRect Item , const void * pItemId , bool Active ) > & RenderItem )
{
vItemIds . resize ( MaxItems ) ;
2014-09-19 21:52:09 +00:00
2023-08-22 18:45:37 +00:00
vec2 ScrollOffset ( 0.0f , 0.0f ) ;
CScrollRegionParams ScrollParams ;
ScrollParams . m_ScrollbarWidth = 10.0f ;
ScrollParams . m_ScrollbarMargin = 3.0f ;
ScrollParams . m_ScrollUnit = 2.0f * ItemHeight ;
ScrollRegion . Begin ( & View , & ScrollOffset , & ScrollParams ) ;
View . y + = ScrollOffset . y ;
CUIRect Row ;
int ColumnIndex = 0 ;
for ( int ItemIndex = 0 ; ItemIndex < MaxItems ; + + ItemIndex )
{
CUIRect Item ;
if ( ColumnIndex = = 0 )
View . HSplitTop ( ItemHeight , & Row , & View ) ;
Row . VSplitLeft ( View . w / ItemsPerRow , & Item , & Row ) ;
ColumnIndex = ( ColumnIndex + 1 ) % ItemsPerRow ;
if ( ! ScrollRegion . AddRect ( Item ) )
continue ;
2014-09-19 21:52:09 +00:00
2023-08-22 18:45:37 +00:00
const void * pItemId = & vItemIds [ ItemIndex ] ;
const char * pName = GetItemName ( ItemIndex ) ;
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
const bool Active = ! Filter . Filtered ( pName ) ;
2014-09-19 21:52:09 +00:00
2023-08-22 18:45:37 +00:00
const int Click = UI ( ) - > DoButtonLogic ( pItemId , 0 , & Item ) ;
if ( Click = = 1 | | Click = = 2 )
{
// left/right click to toggle filter
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
if ( Filter . Empty ( ) )
2014-12-14 15:45:18 +00:00
{
2023-08-22 18:45:37 +00:00
if ( Click = = 1 )
2014-09-19 21:52:09 +00:00
{
2023-08-22 18:45:37 +00:00
// Left click: when all are active, only activate one
for ( int j = 0 ; j < MaxItems ; + + j )
2014-12-14 15:45:18 +00:00
{
2023-08-22 18:45:37 +00:00
if ( j ! = ItemIndex )
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
Filter . Add ( GetItemName ( j ) ) ;
2017-08-30 20:36:39 +00:00
}
2023-08-22 18:45:37 +00:00
}
else if ( Click = = 2 )
{
// Right click: when all are active, only deactivate one
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
Filter . Add ( GetItemName ( ItemIndex ) ) ;
2023-08-22 18:45:37 +00:00
}
}
else
{
bool AllFilteredExceptUs = true ;
for ( int j = 0 ; j < MaxItems ; + + j )
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
if ( j ! = ItemIndex & & ! Filter . Filtered ( GetItemName ( j ) ) )
2017-08-30 20:36:39 +00:00
{
2023-08-22 18:45:37 +00:00
AllFilteredExceptUs = false ;
break ;
2017-08-30 20:36:39 +00:00
}
2023-08-22 18:45:37 +00:00
}
// when last one is removed, reset (re-enable all)
if ( AllFilteredExceptUs )
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
Filter . Clear ( ) ;
2023-08-22 18:45:37 +00:00
}
else if ( Active )
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
Filter . Add ( pName ) ;
2023-08-22 18:45:37 +00:00
}
else
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
Filter . Remove ( pName ) ;
2014-09-19 21:52:09 +00:00
}
2014-12-14 15:45:18 +00:00
}
2023-08-22 18:45:37 +00:00
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
Client ( ) - > ServerBrowserUpdate ( ) ;
if ( UpdateCommunityCacheOnChange )
UpdateCommunityCache ( true ) ;
2014-12-14 15:45:18 +00:00
}
2023-08-22 18:45:37 +00:00
else if ( Click = = 3 )
2014-12-14 15:45:18 +00:00
{
2023-08-22 18:45:37 +00:00
// middle click to reset (re-enable all)
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
Filter . Clear ( ) ;
Client ( ) - > ServerBrowserUpdate ( ) ;
if ( UpdateCommunityCacheOnChange )
UpdateCommunityCache ( true ) ;
2023-08-22 18:45:37 +00:00
}
2014-12-14 15:45:18 +00:00
2023-08-22 18:45:37 +00:00
if ( UI ( ) - > HotItem ( ) = = pItemId & & ! ScrollRegion . Animating ( ) )
Item . Draw ( ColorRGBA ( 1.0f , 1.0f , 1.0f , 0.33f ) , IGraphics : : CORNER_ALL , 2.0f ) ;
RenderItem ( ItemIndex , Item , pItemId , Active ) ;
}
2014-12-14 15:45:18 +00:00
2023-08-22 18:45:37 +00:00
ScrollRegion . End ( ) ;
}
2014-12-14 15:45:18 +00:00
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
void CMenus : : RenderServerbrowserCommunitiesFilter ( CUIRect View )
{
const int MaxEntries = ServerBrowser ( ) - > Communities ( ) . size ( ) ;
const int EntriesPerRow = 1 ;
static CScrollRegion s_ScrollRegion ;
static std : : vector < unsigned char > s_vItemIds ;
const float ItemHeight = 13.0f ;
const float Spacing = 2.0f ;
const auto & & GetItemName = [ & ] ( int ItemIndex ) {
return ServerBrowser ( ) - > Communities ( ) [ ItemIndex ] . Id ( ) ;
} ;
const auto & & GetItemDisplayName = [ & ] ( int ItemIndex ) {
return ServerBrowser ( ) - > Communities ( ) [ ItemIndex ] . Name ( ) ;
} ;
const auto & & RenderItem = [ & ] ( int ItemIndex , CUIRect Item , const void * pItemId , bool Active ) {
const float Alpha = ( Active ? 0.9f : 0.2f ) + ( UI ( ) - > HotItem ( ) = = pItemId ? 0.1f : 0.0f ) ;
CUIRect Icon , Label ;
Item . Margin ( Spacing , & Item ) ;
Item . VSplitLeft ( Item . h * 2.0f , & Icon , & Label ) ;
Label . VSplitLeft ( Spacing , nullptr , & Label ) ;
const SCommunityIcon * pIcon = FindCommunityIcon ( GetItemName ( ItemIndex ) ) ;
if ( pIcon ! = nullptr )
{
RenderCommunityIcon ( pIcon , Icon , Active ) ;
}
TextRender ( ) - > TextColor ( 1.0f , 1.0f , 1.0f , Alpha ) ;
UI ( ) - > DoLabel ( & Label , GetItemDisplayName ( ItemIndex ) , Label . h * CUI : : ms_FontmodHeight , TEXTALIGN_ML ) ;
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
} ;
RenderServerbrowserDDNetFilter ( View , ServerBrowser ( ) - > CommunitiesFilter ( ) , ItemHeight + 2.0f * Spacing , MaxEntries , EntriesPerRow , s_ScrollRegion , s_vItemIds , true , GetItemName , RenderItem ) ;
}
void CMenus : : RenderServerbrowserCountriesFilter ( CUIRect View )
2023-08-22 18:45:37 +00:00
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
const int MaxEntries = m_CommunityCache . m_vpSelectableCountries . size ( ) ;
2023-08-22 18:45:37 +00:00
const int EntriesPerRow = MaxEntries > 8 ? 5 : 4 ;
2014-12-14 15:45:18 +00:00
2023-08-22 18:45:37 +00:00
static CScrollRegion s_ScrollRegion ;
static std : : vector < unsigned char > s_vItemIds ;
2014-09-19 21:52:09 +00:00
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
const float ItemHeight = 18.0f ;
2023-08-22 18:45:37 +00:00
const float Spacing = 2.0f ;
2014-12-14 15:45:18 +00:00
2023-08-22 18:45:37 +00:00
const auto & & GetItemName = [ & ] ( int ItemIndex ) {
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
return m_CommunityCache . m_vpSelectableCountries [ ItemIndex ] - > Name ( ) ;
2023-08-22 18:45:37 +00:00
} ;
const auto & & RenderItem = [ & ] ( int ItemIndex , CUIRect Item , const void * pItemId , bool Active ) {
Item . Margin ( Spacing , & Item ) ;
const float OldWidth = Item . w ;
Item . w = Item . h * 2.0f ;
Item . x + = ( OldWidth - Item . w ) / 2.0f ;
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
m_pClient - > m_CountryFlags . Render ( m_CommunityCache . m_vpSelectableCountries [ ItemIndex ] - > FlagId ( ) , ColorRGBA ( 1.0f , 1.0f , 1.0f , ( Active ? 0.9f : 0.2f ) + ( UI ( ) - > HotItem ( ) = = pItemId ? 0.1f : 0.0f ) ) , Item . x , Item . y , Item . w , Item . h ) ;
2023-08-22 18:45:37 +00:00
} ;
2014-12-14 15:45:18 +00:00
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
RenderServerbrowserDDNetFilter ( View , ServerBrowser ( ) - > CountriesFilter ( ) , ItemHeight + 2.0f * Spacing , MaxEntries , EntriesPerRow , s_ScrollRegion , s_vItemIds , false , GetItemName , RenderItem ) ;
2023-08-22 18:45:37 +00:00
}
2014-12-14 15:45:18 +00:00
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
void CMenus : : RenderServerbrowserTypesFilter ( CUIRect View )
2023-08-22 18:45:37 +00:00
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
const int MaxEntries = m_CommunityCache . m_vpSelectableTypes . size ( ) ;
2023-08-22 18:45:37 +00:00
const int EntriesPerRow = 3 ;
2014-12-14 15:45:18 +00:00
2023-08-22 18:45:37 +00:00
static CScrollRegion s_ScrollRegion ;
static std : : vector < unsigned char > s_vItemIds ;
2014-09-19 21:52:09 +00:00
2023-08-22 18:45:37 +00:00
const float ItemHeight = 13.0f ;
const float Spacing = 2.0f ;
2014-09-19 21:52:09 +00:00
2023-08-22 18:45:37 +00:00
const auto & & GetItemName = [ & ] ( int ItemIndex ) {
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
return m_CommunityCache . m_vpSelectableTypes [ ItemIndex ] - > Name ( ) ;
2023-08-22 18:45:37 +00:00
} ;
const auto & & RenderItem = [ & ] ( int ItemIndex , CUIRect Item , const void * pItemId , bool Active ) {
Item . Margin ( Spacing , & Item ) ;
TextRender ( ) - > TextColor ( 1.0f , 1.0f , 1.0f , ( Active ? 0.9f : 0.2f ) + ( UI ( ) - > HotItem ( ) = = pItemId ? 0.1f : 0.0f ) ) ;
UI ( ) - > DoLabel ( & Item , GetItemName ( ItemIndex ) , Item . h * CUI : : ms_FontmodHeight , TEXTALIGN_MC ) ;
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
} ;
2014-05-03 15:24:34 +00:00
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
RenderServerbrowserDDNetFilter ( View , ServerBrowser ( ) - > TypesFilter ( ) , ItemHeight + 2.0f * Spacing , MaxEntries , EntriesPerRow , s_ScrollRegion , s_vItemIds , false , GetItemName , RenderItem ) ;
2008-09-04 18:42:26 +00:00
}
2008-08-27 15:48:50 +00:00
2023-05-21 19:17:08 +00:00
CUI : : EPopupMenuFunctionResult CMenus : : PopupCountrySelection ( void * pContext , CUIRect View , bool Active )
{
SPopupCountrySelectionContext * pPopupContext = static_cast < SPopupCountrySelectionContext * > ( pContext ) ;
CMenus * pMenus = pPopupContext - > m_pMenus ;
static CListBox s_ListBox ;
2023-06-07 16:08:55 +00:00
s_ListBox . SetActive ( Active ) ;
s_ListBox . DoStart ( 50.0f , pMenus - > m_pClient - > m_CountryFlags . Num ( ) , 8 , 1 , - 1 , & View , false ) ;
2023-05-21 19:17:08 +00:00
if ( pPopupContext - > m_New )
{
pPopupContext - > m_New = false ;
s_ListBox . ScrollToSelected ( ) ;
}
for ( size_t i = 0 ; i < pMenus - > m_pClient - > m_CountryFlags . Num ( ) ; + + i )
{
const CCountryFlags : : CCountryFlag * pEntry = pMenus - > m_pClient - > m_CountryFlags . GetByIndex ( i ) ;
2023-06-07 16:08:55 +00:00
const CListboxItem Item = s_ListBox . DoNextItem ( pEntry , pEntry - > m_CountryCode = = pPopupContext - > m_Selection ) ;
2023-05-21 19:17:08 +00:00
if ( ! Item . m_Visible )
continue ;
CUIRect FlagRect , Label ;
Item . m_Rect . Margin ( 5.0f , & FlagRect ) ;
FlagRect . HSplitBottom ( 12.0f , & FlagRect , & Label ) ;
Label . HSplitTop ( 2.0f , nullptr , & Label ) ;
const float OldWidth = FlagRect . w ;
FlagRect . w = FlagRect . h * 2.0f ;
FlagRect . x + = ( OldWidth - FlagRect . w ) / 2.0f ;
2023-06-07 15:50:26 +00:00
pMenus - > m_pClient - > m_CountryFlags . Render ( pEntry - > m_CountryCode , ColorRGBA ( 1.0f , 1.0f , 1.0f , 1.0f ) , FlagRect . x , FlagRect . y , FlagRect . w , FlagRect . h ) ;
2023-05-21 19:17:08 +00:00
pMenus - > UI ( ) - > DoLabel ( & Label , pEntry - > m_aCountryCodeString , 10.0f , TEXTALIGN_MC ) ;
}
const int NewSelected = s_ListBox . DoEnd ( ) ;
2023-06-07 16:08:55 +00:00
pPopupContext - > m_Selection = NewSelected > = 0 ? pMenus - > m_pClient - > m_CountryFlags . GetByIndex ( NewSelected ) - > m_CountryCode : - 1 ;
2023-05-21 19:17:08 +00:00
if ( s_ListBox . WasItemSelected ( ) | | s_ListBox . WasItemActivated ( ) )
{
g_Config . m_BrFilterCountry = 1 ;
g_Config . m_BrFilterCountryIndex = pPopupContext - > m_Selection ;
pMenus - > Client ( ) - > ServerBrowserUpdate ( ) ;
return CUI : : POPUP_CLOSE_CURRENT ;
}
return CUI : : POPUP_KEEP_OPEN ;
}
2023-08-22 18:45:37 +00:00
void CMenus : : RenderServerbrowserInfo ( CUIRect View )
2008-09-04 18:42:26 +00:00
{
2010-05-29 07:25:38 +00:00
const CServerInfo * pSelectedServer = ServerBrowser ( ) - > SortedGet ( m_SelectedIndex ) ;
2023-08-22 18:45:37 +00:00
const float RowHeight = 18.0f ;
const float FontSize = ( RowHeight - 4.0f ) * CUI : : ms_FontmodHeight ; // based on DoButton_CheckBox
2008-08-27 15:48:50 +00:00
2023-08-22 18:45:37 +00:00
CUIRect ServerDetails , Scoreboard ;
View . HSplitTop ( 4.0f * 15.0f + RowHeight + 2.0f * 5.0f + 2.0f * 2.0f , & ServerDetails , & Scoreboard ) ;
ServerDetails . Draw ( ColorRGBA ( 0.0f , 0.0f , 0.0f , 0.15f ) , IGraphics : : CORNER_B , 4.0f ) ;
2008-08-27 15:48:50 +00:00
2018-03-13 20:59:07 +00:00
if ( pSelectedServer )
2008-09-04 18:42:26 +00:00
{
2023-01-06 20:14:26 +00:00
ServerDetails . Margin ( 5.0f , & ServerDetails ) ;
2011-03-18 16:59:48 +00:00
2023-01-06 20:14:26 +00:00
// copy info button
{
CUIRect Button ;
ServerDetails . HSplitBottom ( 15.0f , & ServerDetails , & Button ) ;
static CButtonContainer s_CopyButton ;
if ( DoButton_Menu ( & s_CopyButton , Localize ( " Copy info " ) , 0 , & Button ) )
{
char aInfo [ 256 ] ;
pSelectedServer - > InfoToString ( aInfo , sizeof ( aInfo ) ) ;
Input ( ) - > SetClipboardText ( aInfo ) ;
}
}
// favorite checkbox
2008-09-03 20:03:01 +00:00
{
2023-08-22 18:45:37 +00:00
CUIRect ButtonAddFav , ButtonLeakIp ;
ServerDetails . HSplitBottom ( 2.0f , & ServerDetails , nullptr ) ;
ServerDetails . HSplitBottom ( RowHeight , & ServerDetails , & ButtonAddFav ) ;
ServerDetails . HSplitBottom ( 2.0f , & ServerDetails , nullptr ) ;
ButtonAddFav . VSplitMid ( & ButtonAddFav , & ButtonLeakIp ) ;
2010-05-29 07:25:38 +00:00
static int s_AddFavButton = 0 ;
2022-05-23 18:16:18 +00:00
if ( DoButton_CheckBox_Tristate ( & s_AddFavButton , Localize ( " Favorite " ) , pSelectedServer - > m_Favorite , & ButtonAddFav ) )
2008-09-03 20:03:01 +00:00
{
2022-05-23 18:16:18 +00:00
if ( pSelectedServer - > m_Favorite ! = TRISTATE : : NONE )
2021-05-12 19:06:08 +00:00
{
2022-05-23 18:16:18 +00:00
Favorites ( ) - > Remove ( pSelectedServer - > m_aAddresses , pSelectedServer - > m_NumAddresses ) ;
2021-05-12 19:06:08 +00:00
}
2008-09-04 18:42:26 +00:00
else
2021-05-12 19:06:08 +00:00
{
2022-05-23 18:16:18 +00:00
Favorites ( ) - > Add ( pSelectedServer - > m_aAddresses , pSelectedServer - > m_NumAddresses ) ;
2021-05-12 19:06:08 +00:00
if ( g_Config . m_UiPage = = PAGE_LAN )
{
2022-05-23 18:16:18 +00:00
Favorites ( ) - > AllowPing ( pSelectedServer - > m_aAddresses , pSelectedServer - > m_NumAddresses , true ) ;
2021-05-12 19:06:08 +00:00
}
}
2022-05-23 18:16:18 +00:00
Client ( ) - > ServerBrowserUpdate ( ) ;
2021-05-12 19:06:08 +00:00
}
2022-05-23 18:16:18 +00:00
if ( pSelectedServer - > m_Favorite ! = TRISTATE : : NONE )
2021-05-12 19:06:08 +00:00
{
2023-08-22 18:45:37 +00:00
static int s_LeakIpButton = 0 ;
2022-05-23 18:16:18 +00:00
if ( DoButton_CheckBox_Tristate ( & s_LeakIpButton , Localize ( " Leak IP " ) , pSelectedServer - > m_FavoriteAllowPing , & ButtonLeakIp ) )
2021-05-12 19:06:08 +00:00
{
2022-05-23 18:16:18 +00:00
Favorites ( ) - > AllowPing ( pSelectedServer - > m_aAddresses , pSelectedServer - > m_NumAddresses , pSelectedServer - > m_FavoriteAllowPing = = TRISTATE : : NONE ) ;
2023-09-30 13:48:07 +00:00
Client ( ) - > ServerBrowserUpdate ( ) ;
2021-05-12 19:06:08 +00:00
}
2008-09-03 20:03:01 +00:00
}
2008-09-04 18:42:26 +00:00
}
2008-09-03 20:03:01 +00:00
2023-08-30 15:49:28 +00:00
CUIRect LeftColumn , RightColumn , Row ;
2010-05-29 07:25:38 +00:00
ServerDetails . VSplitLeft ( 80.0f , & LeftColumn , & RightColumn ) ;
2008-08-27 15:48:50 +00:00
2023-08-30 15:49:28 +00:00
LeftColumn . HSplitTop ( 15.0f , & Row , & LeftColumn ) ;
UI ( ) - > DoLabel ( & Row , Localize ( " Version " ) , FontSize , TEXTALIGN_ML ) ;
2008-08-27 15:48:50 +00:00
2010-05-29 07:25:38 +00:00
RightColumn . HSplitTop ( 15.0f , & Row , & RightColumn ) ;
2023-06-03 20:59:04 +00:00
UI ( ) - > DoLabel ( & Row , pSelectedServer - > m_aVersion , FontSize , TEXTALIGN_ML ) ;
2008-08-27 15:48:50 +00:00
2023-08-30 15:49:28 +00:00
LeftColumn . HSplitTop ( 15.0f , & Row , & LeftColumn ) ;
UI ( ) - > DoLabel ( & Row , Localize ( " Game type " ) , FontSize , TEXTALIGN_ML ) ;
2010-05-29 07:25:38 +00:00
RightColumn . HSplitTop ( 15.0f , & Row , & RightColumn ) ;
2023-06-03 20:59:04 +00:00
UI ( ) - > DoLabel ( & Row , pSelectedServer - > m_aGameType , FontSize , TEXTALIGN_ML ) ;
2008-08-27 15:48:50 +00:00
2023-08-30 15:49:28 +00:00
LeftColumn . HSplitTop ( 15.0f , & Row , & LeftColumn ) ;
UI ( ) - > DoLabel ( & Row , Localize ( " Ping " ) , FontSize , TEXTALIGN_ML ) ;
2010-05-29 07:25:38 +00:00
char aTemp [ 16 ] ;
2023-08-22 18:45:37 +00:00
FormatServerbrowserPing ( aTemp , pSelectedServer ) ;
2010-05-29 07:25:38 +00:00
RightColumn . HSplitTop ( 15.0f , & Row , & RightColumn ) ;
2023-06-03 20:59:04 +00:00
UI ( ) - > DoLabel ( & Row , aTemp , FontSize , TEXTALIGN_ML ) ;
2023-08-22 18:45:37 +00:00
RenderServerbrowserInfoScoreboard ( Scoreboard , pSelectedServer ) ;
2008-09-04 18:42:26 +00:00
}
2023-06-01 20:29:14 +00:00
else
{
UI ( ) - > DoLabel ( & ServerDetails , Localize ( " No server selected " ) , FontSize , TEXTALIGN_MC ) ;
}
2023-08-22 18:45:37 +00:00
}
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
void CMenus : : RenderServerbrowserInfoScoreboard ( CUIRect View , const CServerInfo * pSelectedServer )
{
const float FontSize = 10.0f ;
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
static CListBox s_ListBox ;
View . VSplitLeft ( 5.0f , nullptr , & View ) ;
if ( ! s_ListBox . ScrollbarShown ( ) )
View . VSplitRight ( 5.0f , & View , nullptr ) ;
s_ListBox . DoAutoSpacing ( 1.0f ) ;
s_ListBox . SetScrollbarWidth ( 16.0f ) ;
s_ListBox . SetScrollbarMargin ( 5.0f ) ;
s_ListBox . DoStart ( 25.0f , pSelectedServer - > m_NumReceivedClients , 1 , 3 , - 1 , & View ) ;
for ( int i = 0 ; i < pSelectedServer - > m_NumReceivedClients ; i + + )
2008-09-04 18:42:26 +00:00
{
2023-08-22 18:45:37 +00:00
const CServerInfo : : CClient & CurrentClient = pSelectedServer - > m_aClients [ i ] ;
const CListboxItem Item = s_ListBox . DoNextItem ( & CurrentClient ) ;
if ( ! Item . m_Visible )
continue ;
2022-10-11 19:52:27 +00:00
2023-08-22 18:45:37 +00:00
CUIRect Skin , Name , Clan , Score , Flag ;
Name = Item . m_Rect ;
2023-10-07 13:05:36 +00:00
ColorRGBA Color ;
2023-10-07 13:52:36 +00:00
const float Alpha = ( i % 2 + 1 ) * 0.05f ;
2023-10-07 13:05:36 +00:00
switch ( CurrentClient . m_FriendState )
{
case IFriends : : FRIEND_NO :
2023-10-07 13:52:36 +00:00
Color = ColorRGBA ( 1.0f , 1.0f , 1.0f , Alpha ) ;
2023-10-07 13:05:36 +00:00
break ;
case IFriends : : FRIEND_PLAYER :
2023-11-02 12:18:00 +00:00
if ( CurrentClient . m_Afk )
Color = ColorRGBA ( 1.0f , 1.0f , 0.5f , 0.15f + Alpha ) ;
else
Color = ColorRGBA ( 0.5f , 1.0f , 0.5f , 0.15f + Alpha ) ;
2023-10-07 13:05:36 +00:00
break ;
case IFriends : : FRIEND_CLAN :
2023-11-02 12:18:00 +00:00
if ( CurrentClient . m_Afk )
Color = ColorRGBA ( 0.4f , 0.75f , 1.0f , 0.15f + Alpha ) ;
else
Color = ColorRGBA ( 0.4f , 0.4f , 1.0f , 0.15f + Alpha ) ;
2023-10-07 13:52:36 +00:00
break ;
default :
dbg_assert ( false , " Invalid friend state " ) ;
dbg_break ( ) ;
2023-10-07 13:05:36 +00:00
break ;
}
2023-08-22 18:45:37 +00:00
Name . Draw ( Color , IGraphics : : CORNER_ALL , 4.0f ) ;
Name . VSplitLeft ( 1.0f , nullptr , & Name ) ;
Name . VSplitLeft ( 34.0f , & Score , & Name ) ;
Name . VSplitLeft ( 18.0f , & Skin , & Name ) ;
Name . VSplitRight ( 26.0f , & Name , & Flag ) ;
Flag . HMargin ( 6.0f , & Flag ) ;
Name . HSplitTop ( 12.0f , & Name , & Clan ) ;
// score
char aTemp [ 16 ] ;
if ( ! CurrentClient . m_Player )
2008-08-27 15:48:50 +00:00
{
2023-08-22 18:45:37 +00:00
str_copy ( aTemp , " SPEC " ) ;
}
else if ( pSelectedServer - > m_ClientScoreKind = = CServerInfo : : CLIENT_SCORE_KIND_POINTS )
{
str_from_int ( CurrentClient . m_Score , aTemp ) ;
}
else
{
std : : optional < int > Time = { } ;
2014-01-24 21:09:52 +00:00
2023-08-22 18:45:37 +00:00
if ( pSelectedServer - > m_ClientScoreKind = = CServerInfo : : CLIENT_SCORE_KIND_TIME_BACKCOMPAT )
2014-02-19 13:24:26 +00:00
{
2023-08-22 18:45:37 +00:00
const int TempTime = absolute ( CurrentClient . m_Score ) ;
if ( TempTime ! = 0 & & TempTime ! = 9999 )
Time = TempTime ;
2011-03-20 14:33:49 +00:00
}
2014-02-19 13:24:26 +00:00
else
2022-10-11 19:52:27 +00:00
{
2023-08-22 18:45:37 +00:00
// CServerInfo::CLIENT_SCORE_KIND_POINTS
if ( CurrentClient . m_Score > = 0 )
Time = CurrentClient . m_Score ;
2022-10-11 19:52:27 +00:00
}
2014-02-19 13:24:26 +00:00
2023-08-22 18:45:37 +00:00
if ( Time . has_value ( ) )
2023-01-07 08:20:25 +00:00
{
2023-08-22 18:45:37 +00:00
str_time ( ( int64_t ) Time . value ( ) * 100 , TIME_HOURS , aTemp , sizeof ( aTemp ) ) ;
}
else
{
aTemp [ 0 ] = ' \0 ' ;
2023-01-07 08:20:25 +00:00
}
2008-08-27 15:48:50 +00:00
}
2014-01-10 11:22:48 +00:00
2023-08-22 18:45:37 +00:00
UI ( ) - > DoLabel ( & Score , aTemp , FontSize , TEXTALIGN_ML ) ;
// render tee if available
if ( CurrentClient . m_aSkin [ 0 ] ! = ' \0 ' )
2023-01-05 11:21:10 +00:00
{
2023-08-22 18:45:37 +00:00
const CTeeRenderInfo TeeInfo = GetTeeRenderInfo ( vec2 ( Skin . w , Skin . h ) , CurrentClient . m_aSkin , CurrentClient . m_CustomSkinColors , CurrentClient . m_CustomSkinColorBody , CurrentClient . m_CustomSkinColorFeet ) ;
const CAnimState * pIdleState = CAnimState : : GetIdle ( ) ;
vec2 OffsetToMid ;
RenderTools ( ) - > GetRenderTeeOffsetToRenderedTee ( pIdleState , & TeeInfo , OffsetToMid ) ;
const vec2 TeeRenderPos = vec2 ( Skin . x + TeeInfo . m_Size / 2.0f , Skin . y + Skin . h / 2.0f + OffsetToMid . y ) ;
2023-11-02 12:18:00 +00:00
RenderTools ( ) - > RenderTee ( pIdleState , & TeeInfo , CurrentClient . m_Afk ? EMOTE_BLINK : EMOTE_NORMAL , vec2 ( 1.0f , 0.0f ) , TeeRenderPos ) ;
2023-01-05 11:21:10 +00:00
}
2023-08-22 18:45:37 +00:00
// name
CTextCursor Cursor ;
TextRender ( ) - > SetCursor ( & Cursor , Name . x , Name . y + ( Name . h - ( FontSize - 1.0f ) ) / 2.0f , FontSize - 1.0f , TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END ) ;
Cursor . m_LineWidth = Name . w ;
const char * pName = CurrentClient . m_aName ;
bool Printed = false ;
if ( g_Config . m_BrFilterString [ 0 ] )
Printed = PrintHighlighted ( pName , [ & ] ( const char * pFilteredStr , const int FilterLen ) {
TextRender ( ) - > TextEx ( & Cursor , pName , ( int ) ( pFilteredStr - pName ) ) ;
TextRender ( ) - > TextColor ( gs_HighlightedTextColor ) ;
TextRender ( ) - > TextEx ( & Cursor , pFilteredStr , FilterLen ) ;
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
TextRender ( ) - > TextEx ( & Cursor , pFilteredStr + FilterLen , - 1 ) ;
} ) ;
if ( ! Printed )
TextRender ( ) - > TextEx ( & Cursor , pName , - 1 ) ;
// clan
TextRender ( ) - > SetCursor ( & Cursor , Clan . x , Clan . y + ( Clan . h - ( FontSize - 2.0f ) ) / 2.0f , FontSize - 2.0f , TEXTFLAG_RENDER | TEXTFLAG_STOP_AT_END ) ;
Cursor . m_LineWidth = Clan . w ;
const char * pClan = CurrentClient . m_aClan ;
Printed = false ;
if ( g_Config . m_BrFilterString [ 0 ] )
Printed = PrintHighlighted ( pClan , [ & ] ( const char * pFilteredStr , const int FilterLen ) {
TextRender ( ) - > TextEx ( & Cursor , pClan , ( int ) ( pFilteredStr - pClan ) ) ;
TextRender ( ) - > TextColor ( 0.4f , 0.4f , 1.0f , 1.0f ) ;
TextRender ( ) - > TextEx ( & Cursor , pFilteredStr , FilterLen ) ;
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
TextRender ( ) - > TextEx ( & Cursor , pFilteredStr + FilterLen , - 1 ) ;
} ) ;
if ( ! Printed )
TextRender ( ) - > TextEx ( & Cursor , pClan , - 1 ) ;
// flag
m_pClient - > m_CountryFlags . Render ( CurrentClient . m_Country , ColorRGBA ( 1.0f , 1.0f , 1.0f , 0.5f ) , Flag . x , Flag . y , Flag . w , Flag . h ) ;
2008-08-27 15:48:50 +00:00
}
2023-08-22 18:45:37 +00:00
const int NewSelected = s_ListBox . DoEnd ( ) ;
if ( s_ListBox . WasItemSelected ( ) )
2022-12-23 22:23:44 +00:00
{
2023-08-22 18:45:37 +00:00
const CServerInfo : : CClient & SelectedClient = pSelectedServer - > m_aClients [ NewSelected ] ;
if ( SelectedClient . m_FriendState = = IFriends : : FRIEND_PLAYER )
m_pClient - > Friends ( ) - > RemoveFriend ( SelectedClient . m_aName , SelectedClient . m_aClan ) ;
2022-12-23 22:23:44 +00:00
else
2023-08-22 18:45:37 +00:00
m_pClient - > Friends ( ) - > AddFriend ( SelectedClient . m_aName , SelectedClient . m_aClan ) ;
FriendlistOnUpdate ( ) ;
Client ( ) - > ServerBrowserUpdate ( ) ;
2022-12-23 22:23:44 +00:00
}
2011-06-26 15:10:13 +00:00
}
2011-03-23 12:06:35 +00:00
void CMenus : : RenderServerbrowserFriends ( CUIRect View )
2008-09-04 18:42:26 +00:00
{
2011-06-26 15:10:13 +00:00
const float FontSize = 10.0f ;
2023-05-17 19:08:32 +00:00
static bool s_aListExtended [ NUM_FRIEND_TYPES ] = { true , true , false } ;
static const ColorRGBA s_aListColors [ NUM_FRIEND_TYPES ] = { ColorRGBA ( 0.5f , 1.0f , 0.5f , 1.0f ) , ColorRGBA ( 0.4f , 0.4f , 1.0f , 1.0f ) , ColorRGBA ( 1.0f , 0.5f , 0.5f , 1.0f ) } ;
2023-09-22 21:26:09 +00:00
// Alternates of s_aListColors include: AFK friend color, AFK clanmate color, Offline clan color.
static const ColorRGBA s_aListColorAlternates [ NUM_FRIEND_TYPES ] = { ColorRGBA ( 1.0f , 1.0f , 0.5f , 1.0f ) , ColorRGBA ( 0.4f , 0.75f , 1.0f , 1.0f ) , ColorRGBA ( 0.7f , 0.45f , 0.75f , 1.0f ) } ;
2023-05-17 19:08:32 +00:00
const float SpacingH = 2.0f ;
2011-03-23 12:06:35 +00:00
2023-08-22 18:45:37 +00:00
CUIRect List , ServerFriends ;
View . Draw ( ColorRGBA ( 0.0f , 0.0f , 0.0f , 0.15f ) , IGraphics : : CORNER_NONE , 0.0f ) ;
View . HSplitBottom ( 70.0f , & List , & ServerFriends ) ;
List . HSplitTop ( 5.0f , nullptr , & List ) ;
List . VSplitLeft ( 5.0f , nullptr , & List ) ;
2010-05-29 07:25:38 +00:00
2023-05-17 19:08:32 +00:00
// calculate friends
// TODO: optimize this
m_pRemoveFriend = nullptr ;
for ( auto & vFriends : m_avFriends )
vFriends . clear ( ) ;
2011-04-13 18:37:12 +00:00
2023-05-17 19:08:32 +00:00
for ( int FriendIndex = 0 ; FriendIndex < m_pClient - > Friends ( ) - > NumFriends ( ) ; + + FriendIndex )
2011-03-23 12:06:35 +00:00
{
2023-05-17 19:08:32 +00:00
m_avFriends [ FRIEND_OFF ] . emplace_back ( m_pClient - > Friends ( ) - > GetFriend ( FriendIndex ) ) ;
2011-03-23 12:06:35 +00:00
}
2011-04-13 18:37:12 +00:00
2023-05-17 19:08:32 +00:00
for ( int ServerIndex = 0 ; ServerIndex < ServerBrowser ( ) - > NumSortedServers ( ) ; + + ServerIndex )
{
const CServerInfo * pEntry = ServerBrowser ( ) - > SortedGet ( ServerIndex ) ;
if ( pEntry - > m_FriendState = = IFriends : : FRIEND_NO )
continue ;
2011-06-26 15:10:13 +00:00
2023-05-17 19:08:32 +00:00
for ( int ClientIndex = 0 ; ClientIndex < pEntry - > m_NumClients ; + + ClientIndex )
{
const CServerInfo : : CClient & CurrentClient = pEntry - > m_aClients [ ClientIndex ] ;
if ( CurrentClient . m_FriendState = = IFriends : : FRIEND_NO )
continue ;
const int FriendIndex = CurrentClient . m_FriendState = = IFriends : : FRIEND_PLAYER ? FRIEND_PLAYER_ON : FRIEND_CLAN_ON ;
2023-05-18 19:34:27 +00:00
m_avFriends [ FriendIndex ] . emplace_back ( CurrentClient , pEntry ) ;
2023-05-17 19:08:32 +00:00
const auto & & RemovalPredicate = [ CurrentClient ] ( const CFriendItem & Friend ) {
return ( Friend . Name ( ) [ 0 ] = = ' \0 ' | | str_comp ( Friend . Name ( ) , CurrentClient . m_aName ) = = 0 ) & & ( ( Friend . Name ( ) [ 0 ] ! = ' \0 ' & & g_Config . m_ClFriendsIgnoreClan ) | | str_comp ( Friend . Clan ( ) , CurrentClient . m_aClan ) = = 0 ) ;
} ;
m_avFriends [ FRIEND_OFF ] . erase ( std : : remove_if ( m_avFriends [ FRIEND_OFF ] . begin ( ) , m_avFriends [ FRIEND_OFF ] . end ( ) , RemovalPredicate ) , m_avFriends [ FRIEND_OFF ] . end ( ) ) ;
}
}
for ( auto & vFriends : m_avFriends )
std : : sort ( vFriends . begin ( ) , vFriends . end ( ) ) ;
// friends list
static CScrollRegion s_ScrollRegion ;
2023-09-06 21:44:58 +00:00
if ( ! s_ScrollRegion . ScrollbarShown ( ) )
2023-08-22 18:45:37 +00:00
List . VSplitRight ( 5.0f , & List , nullptr ) ;
2023-05-17 19:08:32 +00:00
vec2 ScrollOffset ( 0.0f , 0.0f ) ;
CScrollRegionParams ScrollParams ;
2023-08-22 18:45:37 +00:00
ScrollParams . m_ScrollbarWidth = 16.0f ;
ScrollParams . m_ScrollbarMargin = 5.0f ;
2023-05-17 19:08:32 +00:00
ScrollParams . m_ScrollUnit = 80.0f ;
s_ScrollRegion . Begin ( & List , & ScrollOffset , & ScrollParams ) ;
List . y + = ScrollOffset . y ;
2023-08-22 18:45:37 +00:00
char aBuf [ 256 ] ;
2023-05-17 19:08:32 +00:00
for ( size_t FriendType = 0 ; FriendType < NUM_FRIEND_TYPES ; + + FriendType )
2011-06-26 15:10:13 +00:00
{
2023-05-17 19:08:32 +00:00
// header
CUIRect Header , GroupIcon , GroupLabel ;
List . HSplitTop ( ms_ListheaderHeight , & Header , & List ) ;
s_ScrollRegion . AddRect ( Header ) ;
2023-08-22 18:45:37 +00:00
Header . Draw ( ColorRGBA ( 1.0f , 1.0f , 1.0f , UI ( ) - > HotItem ( ) = = & s_aListExtended [ FriendType ] ? 0.4f : 0.25f ) , IGraphics : : CORNER_ALL , 5.0f ) ;
2023-05-17 19:08:32 +00:00
Header . VSplitLeft ( Header . h , & GroupIcon , & GroupLabel ) ;
GroupIcon . Margin ( 2.0f , & GroupIcon ) ;
2023-07-17 13:49:41 +00:00
TextRender ( ) - > SetFontPreset ( EFontPreset : : ICON_FONT ) ;
2023-08-22 18:45:37 +00:00
TextRender ( ) - > TextColor ( UI ( ) - > HotItem ( ) = = & s_aListExtended [ FriendType ] ? TextRender ( ) - > DefaultTextColor ( ) : ColorRGBA ( 0.6f , 0.6f , 0.6f , 1.0f ) ) ;
2023-05-17 19:08:32 +00:00
UI ( ) - > DoLabel ( & GroupIcon , s_aListExtended [ FriendType ] ? FONT_ICON_SQUARE_MINUS : FONT_ICON_SQUARE_PLUS , GroupIcon . h * CUI : : ms_FontmodHeight , TEXTALIGN_MC ) ;
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
2023-07-17 13:49:41 +00:00
TextRender ( ) - > SetFontPreset ( EFontPreset : : DEFAULT_FONT ) ;
2023-05-17 19:08:32 +00:00
switch ( FriendType )
2011-06-26 15:10:13 +00:00
{
2023-05-17 19:08:32 +00:00
case FRIEND_PLAYER_ON :
str_format ( aBuf , sizeof ( aBuf ) , Localize ( " Online players (%d) " ) , ( int ) m_avFriends [ FriendType ] . size ( ) ) ;
break ;
case FRIEND_CLAN_ON :
str_format ( aBuf , sizeof ( aBuf ) , Localize ( " Online clanmates (%d) " ) , ( int ) m_avFriends [ FriendType ] . size ( ) ) ;
break ;
case FRIEND_OFF :
str_format ( aBuf , sizeof ( aBuf ) , Localize ( " Offline (%d) " , " friends (server browser) " ) , ( int ) m_avFriends [ FriendType ] . size ( ) ) ;
break ;
default :
dbg_assert ( false , " FriendType invalid " ) ;
break ;
}
UI ( ) - > DoLabel ( & GroupLabel , aBuf , FontSize , TEXTALIGN_ML ) ;
if ( UI ( ) - > DoButtonLogic ( & s_aListExtended [ FriendType ] , 0 , & Header ) )
{
s_aListExtended [ FriendType ] = ! s_aListExtended [ FriendType ] ;
}
// entries
if ( s_aListExtended [ FriendType ] )
{
for ( size_t FriendIndex = 0 ; FriendIndex < m_avFriends [ FriendType ] . size ( ) ; + + FriendIndex )
2011-06-26 15:10:13 +00:00
{
2023-05-19 13:14:46 +00:00
// space
2023-05-17 19:08:32 +00:00
{
CUIRect Space ;
List . HSplitTop ( SpacingH , & Space , & List ) ;
s_ScrollRegion . AddRect ( Space ) ;
}
2023-05-19 13:14:46 +00:00
CUIRect Rect ;
const auto & Friend = m_avFriends [ FriendType ] [ FriendIndex ] ;
2023-05-19 17:22:11 +00:00
List . HSplitTop ( 11.0f + 10.0f + 2 * 2.0f + 1.0f + ( Friend . ServerInfo ( ) = = nullptr ? 0.0f : 10.0f ) , & Rect , & List ) ;
2023-05-19 13:14:46 +00:00
s_ScrollRegion . AddRect ( Rect ) ;
2023-09-06 21:44:58 +00:00
if ( s_ScrollRegion . RectClipped ( Rect ) )
2023-05-17 19:08:32 +00:00
continue ;
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
const bool Inside = UI ( ) - > HotItem ( ) = = Friend . ListItemId ( ) | | UI ( ) - > HotItem ( ) = = Friend . RemoveButtonId ( ) | | UI ( ) - > HotItem ( ) = = Friend . CommunityTooltipId ( ) ;
2023-08-22 18:45:37 +00:00
bool ButtonResult = UI ( ) - > DoButtonLogic ( Friend . ListItemId ( ) , 0 , & Rect ) ;
2023-05-17 19:08:32 +00:00
if ( Friend . ServerInfo ( ) )
{
GameClient ( ) - > m_Tooltips . DoToolTip ( Friend . ListItemId ( ) , & Rect , Localize ( " Click to select server. Double click to join your friend. " ) ) ;
}
2023-09-22 21:26:09 +00:00
const bool AlternateColor = ( FriendType ! = FRIEND_OFF & & Friend . IsAfk ( ) ) | | ( Friend . FriendState ( ) = = IFriends : : FRIEND_CLAN & & FriendType = = FRIEND_OFF ) ;
Rect . Draw ( ( AlternateColor ? s_aListColorAlternates [ FriendType ] : s_aListColors [ FriendType ] ) . WithAlpha ( Inside ? 0.5f : 0.3f ) , IGraphics : : CORNER_ALL , 5.0f ) ;
2023-05-17 19:08:32 +00:00
Rect . Margin ( 2.0f , & Rect ) ;
2023-05-18 19:34:27 +00:00
CUIRect RemoveButton , NameLabel , ClanLabel , InfoLabel ;
2023-05-17 19:08:32 +00:00
Rect . HSplitTop ( 16.0f , & RemoveButton , nullptr ) ;
RemoveButton . VSplitRight ( 13.0f , nullptr , & RemoveButton ) ;
RemoveButton . HMargin ( ( RemoveButton . h - RemoveButton . w ) / 2.0f , & RemoveButton ) ;
Rect . VSplitLeft ( 2.0f , nullptr , & Rect ) ;
2023-05-18 19:34:27 +00:00
if ( Friend . ServerInfo ( ) )
Rect . HSplitBottom ( 10.0f , & Rect , & InfoLabel ) ;
2023-05-19 17:22:11 +00:00
Rect . HSplitTop ( 11.0f + 10.0f , & Rect , nullptr ) ;
2023-05-18 19:34:27 +00:00
// tee
if ( Friend . Skin ( ) [ 0 ] ! = ' \0 ' )
{
CUIRect Skin ;
Rect . VSplitLeft ( Rect . h , & Skin , & Rect ) ;
Rect . VSplitLeft ( 2.0f , nullptr , & Rect ) ;
2023-08-22 18:45:37 +00:00
const CTeeRenderInfo TeeInfo = GetTeeRenderInfo ( vec2 ( Skin . w , Skin . h ) , Friend . Skin ( ) , Friend . CustomSkinColors ( ) , Friend . CustomSkinColorBody ( ) , Friend . CustomSkinColorFeet ( ) ) ;
2023-05-30 22:08:01 +00:00
const CAnimState * pIdleState = CAnimState : : GetIdle ( ) ;
2023-05-18 19:34:27 +00:00
vec2 OffsetToMid ;
RenderTools ( ) - > GetRenderTeeOffsetToRenderedTee ( pIdleState , & TeeInfo , OffsetToMid ) ;
2023-08-22 18:45:37 +00:00
const vec2 TeeRenderPos = vec2 ( Skin . x + Skin . w / 2.0f , Skin . y + Skin . h * 0.55f + OffsetToMid . y ) ;
2023-09-22 21:26:09 +00:00
RenderTools ( ) - > RenderTee ( pIdleState , & TeeInfo , Friend . IsAfk ( ) ? EMOTE_BLINK : EMOTE_NORMAL , vec2 ( 1.0f , 0.0f ) , TeeRenderPos ) ;
2023-05-18 19:34:27 +00:00
}
2023-05-19 17:22:11 +00:00
Rect . HSplitTop ( 11.0f , & NameLabel , & ClanLabel ) ;
2023-05-18 19:34:27 +00:00
2023-05-17 19:08:32 +00:00
// name
2023-05-19 17:22:11 +00:00
UI ( ) - > DoLabel ( & NameLabel , Friend . Name ( ) , FontSize - 1.0f , TEXTALIGN_ML ) ;
2023-05-17 19:08:32 +00:00
// clan
2023-05-18 19:34:27 +00:00
UI ( ) - > DoLabel ( & ClanLabel , Friend . Clan ( ) , FontSize - 2.0f , TEXTALIGN_ML ) ;
2023-05-17 19:08:32 +00:00
2023-05-19 13:15:44 +00:00
// server info
2023-05-17 19:08:32 +00:00
if ( Friend . ServerInfo ( ) )
2011-06-26 15:10:13 +00:00
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
// community icon
const CCommunity * pCommunity = ServerBrowser ( ) - > Community ( Friend . ServerInfo ( ) - > m_aCommunityId ) ;
if ( pCommunity ! = nullptr )
2023-05-19 13:15:44 +00:00
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
const SCommunityIcon * pIcon = FindCommunityIcon ( pCommunity - > Id ( ) ) ;
if ( pIcon ! = nullptr )
{
CUIRect CommunityIcon ;
InfoLabel . VSplitLeft ( 21.0f , & CommunityIcon , & InfoLabel ) ;
InfoLabel . VSplitLeft ( 2.0f , nullptr , & InfoLabel ) ;
RenderCommunityIcon ( pIcon , CommunityIcon , true ) ;
UI ( ) - > DoButtonLogic ( Friend . CommunityTooltipId ( ) , 0 , & CommunityIcon ) ;
GameClient ( ) - > m_Tooltips . DoToolTip ( Friend . CommunityTooltipId ( ) , & CommunityIcon , pCommunity - > Name ( ) ) ;
}
2023-05-19 13:15:44 +00:00
}
// server info text
2023-05-18 20:39:55 +00:00
char aLatency [ 16 ] ;
2023-08-22 18:45:37 +00:00
FormatServerbrowserPing ( aLatency , Friend . ServerInfo ( ) ) ;
2023-05-18 20:39:55 +00:00
if ( aLatency [ 0 ] ! = ' \0 ' )
str_format ( aBuf , sizeof ( aBuf ) , " %s | %s | %s " , Friend . ServerInfo ( ) - > m_aMap , Friend . ServerInfo ( ) - > m_aGameType , aLatency ) ;
2023-05-17 19:08:32 +00:00
else
2023-05-18 20:39:55 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s | %s " , Friend . ServerInfo ( ) - > m_aMap , Friend . ServerInfo ( ) - > m_aGameType ) ;
2023-05-18 19:34:27 +00:00
UI ( ) - > DoLabel ( & InfoLabel , aBuf , FontSize - 2.0f , TEXTALIGN_ML ) ;
2023-05-17 19:08:32 +00:00
}
// remove button
2023-08-22 18:45:37 +00:00
if ( Inside )
2023-05-17 19:08:32 +00:00
{
2023-08-22 18:45:37 +00:00
TextRender ( ) - > TextColor ( UI ( ) - > HotItem ( ) = = Friend . RemoveButtonId ( ) ? TextRender ( ) - > DefaultTextColor ( ) : ColorRGBA ( 0.4f , 0.4f , 0.4f , 1.0f ) ) ;
TextRender ( ) - > SetFontPreset ( EFontPreset : : ICON_FONT ) ;
TextRender ( ) - > SetRenderFlags ( ETextRenderFlags : : TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_OVERSIZE ) ;
UI ( ) - > DoLabel ( & RemoveButton , FONT_ICON_TRASH , RemoveButton . h * CUI : : ms_FontmodHeight , TEXTALIGN_MC ) ;
TextRender ( ) - > SetRenderFlags ( 0 ) ;
TextRender ( ) - > SetFontPreset ( EFontPreset : : DEFAULT_FONT ) ;
TextRender ( ) - > TextColor ( TextRender ( ) - > DefaultTextColor ( ) ) ;
if ( UI ( ) - > DoButtonLogic ( Friend . RemoveButtonId ( ) , 0 , & RemoveButton ) )
{
m_pRemoveFriend = & Friend ;
ButtonResult = false ;
}
GameClient ( ) - > m_Tooltips . DoToolTip ( Friend . RemoveButtonId ( ) , & RemoveButton , Friend . FriendState ( ) = = IFriends : : FRIEND_PLAYER ? Localize ( " Click to remove this player from your friends list. " ) : Localize ( " Click to remove this clan from your friends list. " ) ) ;
2023-05-17 19:08:32 +00:00
}
// handle click and double click on item
if ( ButtonResult & & Friend . ServerInfo ( ) )
{
str_copy ( g_Config . m_UiServerAddress , Friend . ServerInfo ( ) - > m_aAddress ) ;
2023-07-15 08:43:33 +00:00
m_ServerBrowserShouldRevealSelection = true ;
2023-05-17 19:08:32 +00:00
if ( Input ( ) - > MouseDoubleClick ( ) )
2011-06-26 15:10:13 +00:00
{
2023-05-19 18:31:59 +00:00
Connect ( g_Config . m_UiServerAddress ) ;
2011-06-26 15:10:13 +00:00
}
}
}
2023-05-17 19:08:32 +00:00
if ( m_avFriends [ FriendType ] . empty ( ) )
{
CUIRect Label ;
List . HSplitTop ( 12.0f , & Label , & List ) ;
s_ScrollRegion . AddRect ( Label ) ;
UI ( ) - > DoLabel ( & Label , Localize ( " None " ) , Label . h * CUI : : ms_FontmodHeight , TEXTALIGN_ML ) ;
}
2011-06-26 15:10:13 +00:00
}
2011-03-23 12:06:35 +00:00
2023-05-17 19:08:32 +00:00
// space
2022-11-30 21:50:51 +00:00
{
2023-05-17 19:08:32 +00:00
CUIRect Space ;
List . HSplitTop ( SpacingH , & Space , & List ) ;
s_ScrollRegion . AddRect ( Space ) ;
2022-11-30 21:50:51 +00:00
}
2011-03-23 12:06:35 +00:00
}
2023-05-17 19:08:32 +00:00
s_ScrollRegion . End ( ) ;
if ( m_pRemoveFriend ! = nullptr )
{
char aMessage [ 256 ] ;
str_format ( aMessage , sizeof ( aMessage ) ,
m_pRemoveFriend - > FriendState ( ) = = IFriends : : FRIEND_PLAYER ? Localize ( " Are you sure that you want to remove the player '%s' from your friends list? " ) : Localize ( " Are you sure that you want to remove the clan '%s' from your friends list? " ) ,
m_pRemoveFriend - > FriendState ( ) = = IFriends : : FRIEND_PLAYER ? m_pRemoveFriend - > Name ( ) : m_pRemoveFriend - > Clan ( ) ) ;
PopupConfirm ( Localize ( " Remove friend " ) , aMessage , Localize ( " Yes " ) , Localize ( " No " ) , & CMenus : : PopupConfirmRemoveFriend ) ;
}
2011-03-23 12:06:35 +00:00
// add friend
if ( m_pClient - > Friends ( ) - > NumFriends ( ) < IFriends : : MAX_FRIENDS )
{
2023-05-17 19:08:32 +00:00
CUIRect Button ;
2023-08-22 18:45:37 +00:00
ServerFriends . Margin ( 5.0f , & ServerFriends ) ;
2023-05-17 19:08:32 +00:00
ServerFriends . HSplitTop ( 18.0f , & Button , & ServerFriends ) ;
2011-03-23 12:06:35 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s: " , Localize ( " Name " ) ) ;
2023-05-17 19:08:32 +00:00
UI ( ) - > DoLabel ( & Button , aBuf , FontSize + 2.0f , TEXTALIGN_ML ) ;
Button . VSplitLeft ( 80.0f , nullptr , & Button ) ;
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
static CLineInputBuffered < MAX_NAME_LENGTH > s_NameInput ;
UI ( ) - > DoEditBox ( & s_NameInput , & Button , FontSize + 2.0f ) ;
2011-03-23 12:06:35 +00:00
2023-05-17 19:08:32 +00:00
ServerFriends . HSplitTop ( 3.0f , nullptr , & ServerFriends ) ;
ServerFriends . HSplitTop ( 18.0f , & Button , & ServerFriends ) ;
2011-03-23 12:06:35 +00:00
str_format ( aBuf , sizeof ( aBuf ) , " %s: " , Localize ( " Clan " ) ) ;
2023-05-17 19:08:32 +00:00
UI ( ) - > DoLabel ( & Button , aBuf , FontSize + 2.0f , TEXTALIGN_ML ) ;
Button . VSplitLeft ( 80.0f , nullptr , & Button ) ;
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
static CLineInputBuffered < MAX_CLAN_LENGTH > s_ClanInput ;
UI ( ) - > DoEditBox ( & s_ClanInput , & Button , FontSize + 2.0f ) ;
2011-03-23 12:06:35 +00:00
2023-05-17 19:08:32 +00:00
ServerFriends . HSplitTop ( 3.0f , nullptr , & ServerFriends ) ;
ServerFriends . HSplitTop ( 18.0f , & Button , & ServerFriends ) ;
2022-07-16 13:32:06 +00:00
static CButtonContainer s_AddButton ;
2023-05-17 19:08:32 +00:00
if ( DoButton_Menu ( & s_AddButton , s_NameInput . IsEmpty ( ) & & ! s_ClanInput . IsEmpty ( ) ? Localize ( " Add Clan " ) : Localize ( " Add Friend " ) , 0 , & Button ) )
2011-03-23 12:06:35 +00:00
{
Port line input and IME support from 0.7
Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397.
General
------------------------------
Fix issues with the text input. Closes #4346. Closes #4524.
Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference.
Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved.
UI text input
------------------------------
Fix inconsistent mouse-based left and right scrolling (closes #4347).
Support smooth left and right scrolling.
Chat
------------------------------
Support keyboard-based text selection of the chat input.
Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor.
Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling.
Console
------------------------------
Also support mouse-based text selection of the command input.
Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console.
Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice).
When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log.
Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected.
Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end.
Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead.
IME support
------------------------------
Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems.
Improve composition rendering by underlining the composition text instead of putting it in square brackets.
Track active input globally to properly activate and deactivate IME through the SDL functions.
Closes #1030. Closes #1008.
Password rendering
------------------------------
Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint.
Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could:
1. Use a latin password and switch off the IME for the password input with the IME hotkey.
2. Blank your screen with an external program while you are streaming and entering passwords.
3. Use binds to authenticate in rcon or to set the server browser password.
Refactoring
------------------------------
Move all text input logic and general rendering to `CLineInput`.
A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead).
Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer.
Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input.
Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text.
Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input.
Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer.
Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`.
Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering.
Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer.
Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use.
IME usage guide (Windows)
------------------------------
1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean).
2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally.
2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing).
3. Switch from Latin/English input mode to the respective asian input mode.
- Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings.
- Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings.
- Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet.
- Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately.
4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list.
SDL version-specific issues
------------------------------
- 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor.
- 2.0.18, 2.0.20: IME candidates work.
- 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode.
- 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_pClient - > Friends ( ) - > AddFriend ( s_NameInput . GetString ( ) , s_ClanInput . GetString ( ) ) ;
s_NameInput . Clear ( ) ;
s_ClanInput . Clear ( ) ;
2011-06-26 15:10:13 +00:00
FriendlistOnUpdate ( ) ;
2011-03-23 12:06:35 +00:00
Client ( ) - > ServerBrowserUpdate ( ) ;
}
}
}
2023-08-22 18:45:37 +00:00
void CMenus : : FriendlistOnUpdate ( )
{
// TODO: friends are currently updated every frame; optimize and only update friends when necessary
}
2022-11-30 21:50:51 +00:00
void CMenus : : PopupConfirmRemoveFriend ( )
{
2023-07-04 16:16:18 +00:00
m_pClient - > Friends ( ) - > RemoveFriend ( m_pRemoveFriend - > FriendState ( ) = = IFriends : : FRIEND_PLAYER ? m_pRemoveFriend - > Name ( ) : " " , m_pRemoveFriend - > Clan ( ) ) ;
2022-11-30 21:50:51 +00:00
FriendlistOnUpdate ( ) ;
Client ( ) - > ServerBrowserUpdate ( ) ;
2023-05-17 19:08:32 +00:00
m_pRemoveFriend = nullptr ;
2022-11-30 21:50:51 +00:00
}
2023-08-22 18:45:37 +00:00
enum
{
UI_TOOLBOX_PAGE_FILTERS = 0 ,
UI_TOOLBOX_PAGE_INFO ,
UI_TOOLBOX_PAGE_FRIENDS ,
NUM_UI_TOOLBOX_PAGES ,
} ;
void CMenus : : RenderServerbrowserTabBar ( CUIRect TabBar )
{
CUIRect FilterTabButton , InfoTabButton , FriendsTabButton ;
TabBar . VSplitLeft ( TabBar . w / 3.0f , & FilterTabButton , & TabBar ) ;
TabBar . VSplitMid ( & InfoTabButton , & FriendsTabButton ) ;
const ColorRGBA ColorActive = ColorRGBA ( 0.0f , 0.0f , 0.0f , 0.3f ) ;
const ColorRGBA ColorInactive = ColorRGBA ( 0.0f , 0.0f , 0.0f , 0.15f ) ;
if ( ! UI ( ) - > IsPopupOpen ( ) & & UI ( ) - > ConsumeHotkey ( CUI : : HOTKEY_TAB ) )
{
const int Direction = Input ( ) - > ShiftIsPressed ( ) ? - 1 : 1 ;
g_Config . m_UiToolboxPage = ( g_Config . m_UiToolboxPage + NUM_UI_TOOLBOX_PAGES + Direction ) % NUM_UI_TOOLBOX_PAGES ;
}
TextRender ( ) - > SetFontPreset ( EFontPreset : : ICON_FONT ) ;
TextRender ( ) - > SetRenderFlags ( ETextRenderFlags : : TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags : : TEXT_RENDER_FLAG_NO_OVERSIZE ) ;
static CButtonContainer s_FilterTabButton ;
if ( DoButton_MenuTab ( & s_FilterTabButton , FONT_ICON_LIST_UL , g_Config . m_UiToolboxPage = = UI_TOOLBOX_PAGE_FILTERS , & FilterTabButton , IGraphics : : CORNER_T , & m_aAnimatorsSmallPage [ SMALL_TAB_BROWSER_FILTER ] , & ColorInactive , & ColorActive ) )
g_Config . m_UiToolboxPage = UI_TOOLBOX_PAGE_FILTERS ;
static CButtonContainer s_InfoTabButton ;
if ( DoButton_MenuTab ( & s_InfoTabButton , FONT_ICON_INFO , g_Config . m_UiToolboxPage = = UI_TOOLBOX_PAGE_INFO , & InfoTabButton , IGraphics : : CORNER_T , & m_aAnimatorsSmallPage [ SMALL_TAB_BROWSER_INFO ] , & ColorInactive , & ColorActive ) )
g_Config . m_UiToolboxPage = UI_TOOLBOX_PAGE_INFO ;
static CButtonContainer s_FriendsTabButton ;
if ( DoButton_MenuTab ( & s_FriendsTabButton , FONT_ICON_HEART , g_Config . m_UiToolboxPage = = UI_TOOLBOX_PAGE_FRIENDS , & FriendsTabButton , IGraphics : : CORNER_T , & m_aAnimatorsSmallPage [ SMALL_TAB_BROWSER_FRIENDS ] , & ColorInactive , & ColorActive ) )
g_Config . m_UiToolboxPage = UI_TOOLBOX_PAGE_FRIENDS ;
TextRender ( ) - > SetRenderFlags ( 0 ) ;
TextRender ( ) - > SetFontPreset ( EFontPreset : : DEFAULT_FONT ) ;
}
void CMenus : : RenderServerbrowserToolBox ( CUIRect ToolBox )
{
ToolBox . Draw ( ColorRGBA ( 0.0f , 0.0f , 0.0f , 0.15f ) , IGraphics : : CORNER_B , 4.0f ) ;
switch ( g_Config . m_UiToolboxPage )
{
case UI_TOOLBOX_PAGE_FILTERS :
RenderServerbrowserFilters ( ToolBox ) ;
return ;
case UI_TOOLBOX_PAGE_INFO :
RenderServerbrowserInfo ( ToolBox ) ;
return ;
case UI_TOOLBOX_PAGE_FRIENDS :
RenderServerbrowserFriends ( ToolBox ) ;
return ;
default :
dbg_assert ( false , " ui_toolbox_page invalid " ) ;
return ;
}
}
2010-05-29 07:25:38 +00:00
void CMenus : : RenderServerbrowser ( CUIRect MainView )
2008-09-04 18:42:26 +00:00
{
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
UpdateCommunityCache ( false ) ;
UpdateCommunityIcons ( ) ;
2008-09-04 18:42:26 +00:00
/*
2023-08-22 18:45:37 +00:00
+ - - - - - - - - - - - - - - - - - + + - - tabs - - +
| | | |
| | | |
| server list | | tool |
| | | box |
| | | |
+ - - - - - - - - - - - - - - - - - + | |
status box + - - - - - - - - +
2008-09-04 18:42:26 +00:00
*/
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
CUIRect ServerList , StatusBox , ToolBox , TabBar ;
2022-08-07 16:12:07 +00:00
MainView . Draw ( ms_ColorTabbarActive , IGraphics : : CORNER_B , 10.0f ) ;
2011-03-18 16:59:48 +00:00
MainView . Margin ( 10.0f , & MainView ) ;
MainView . VSplitRight ( 205.0f , & ServerList , & ToolBox ) ;
2023-08-22 18:45:37 +00:00
ServerList . VSplitRight ( 5.0f , & ServerList , nullptr ) ;
ToolBox . HSplitTop ( 24.0f , & TabBar , & ToolBox ) ;
ServerList . HSplitBottom ( 65.0f , & ServerList , & StatusBox ) ;
2008-09-04 18:42:26 +00:00
2023-08-22 18:45:37 +00:00
bool WasListboxItemActivated ;
RenderServerbrowserServerList ( ServerList , WasListboxItemActivated ) ;
RenderServerbrowserStatusBox ( StatusBox , WasListboxItemActivated ) ;
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
RenderServerbrowserTabBar ( TabBar ) ;
RenderServerbrowserToolBox ( ToolBox ) ;
}
2010-05-29 07:25:38 +00:00
2023-08-22 18:45:37 +00:00
template < typename F >
bool CMenus : : PrintHighlighted ( const char * pName , F & & PrintFn )
{
const char * pStr = g_Config . m_BrFilterString ;
char aFilterStr [ sizeof ( g_Config . m_BrFilterString ) ] ;
while ( ( pStr = str_next_token ( pStr , IServerBrowser : : SEARCH_EXCLUDE_TOKEN , aFilterStr , sizeof ( aFilterStr ) ) ) )
2020-09-16 01:30:03 +00:00
{
2023-08-22 18:45:37 +00:00
// highlight the parts that matches
const char * pFilteredStr ;
int FilterLen = str_length ( aFilterStr ) ;
if ( aFilterStr [ 0 ] = = ' " ' & & aFilterStr [ FilterLen - 1 ] = = ' " ' )
{
aFilterStr [ FilterLen - 1 ] = ' \0 ' ;
pFilteredStr = str_comp ( pName , & aFilterStr [ 1 ] ) = = 0 ? pName : nullptr ;
FilterLen - = 2 ;
}
else
{
const char * pFilteredStrEnd ;
pFilteredStr = str_utf8_find_nocase ( pName , aFilterStr , & pFilteredStrEnd ) ;
if ( pFilteredStr ! = nullptr & & pFilteredStrEnd ! = nullptr )
FilterLen = pFilteredStrEnd - pFilteredStr ;
}
if ( pFilteredStr )
{
PrintFn ( pFilteredStr , FilterLen ) ;
return true ;
}
2020-09-16 01:30:03 +00:00
}
2023-08-22 18:45:37 +00:00
return false ;
}
2020-09-16 01:30:03 +00:00
2023-08-22 18:45:37 +00:00
CTeeRenderInfo CMenus : : GetTeeRenderInfo ( vec2 Size , const char * pSkinName , bool CustomSkinColors , int CustomSkinColorBody , int CustomSkinColorFeet ) const
{
const CSkin * pSkin = m_pClient - > m_Skins . Find ( pSkinName ) ;
CTeeRenderInfo TeeInfo ;
TeeInfo . m_OriginalRenderSkin = pSkin - > m_OriginalSkin ;
TeeInfo . m_ColorableRenderSkin = pSkin - > m_ColorableSkin ;
TeeInfo . m_SkinMetrics = pSkin - > m_Metrics ;
TeeInfo . m_CustomColoredSkin = CustomSkinColors ;
if ( CustomSkinColors )
{
TeeInfo . m_ColorBody = color_cast < ColorRGBA > ( ColorHSLA ( CustomSkinColorBody ) . UnclampLighting ( ) ) ;
TeeInfo . m_ColorFeet = color_cast < ColorRGBA > ( ColorHSLA ( CustomSkinColorFeet ) . UnclampLighting ( ) ) ;
}
else
2008-09-04 18:42:26 +00:00
{
2023-08-22 18:45:37 +00:00
TeeInfo . m_ColorBody = ColorRGBA ( 1.0f , 1.0f , 1.0f ) ;
TeeInfo . m_ColorFeet = ColorRGBA ( 1.0f , 1.0f , 1.0f ) ;
2011-03-18 16:59:48 +00:00
}
2023-08-22 18:45:37 +00:00
TeeInfo . m_Size = minimum ( Size . x , Size . y ) ;
return TeeInfo ;
2008-08-27 15:48:50 +00:00
}
2010-07-04 14:10:00 +00:00
2011-06-26 15:10:13 +00:00
void CMenus : : ConchainFriendlistUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
2023-09-20 16:32:34 +00:00
CMenus * pThis = ( ( CMenus * ) pUserData ) ;
if ( pResult - > NumArguments ( ) > = 1 & & ( pThis - > Client ( ) - > State ( ) = = IClient : : STATE_OFFLINE | | pThis - > Client ( ) - > State ( ) = = IClient : : STATE_ONLINE ) )
2011-06-26 15:10:13 +00:00
{
2023-09-20 16:32:34 +00:00
pThis - > FriendlistOnUpdate ( ) ;
pThis - > Client ( ) - > ServerBrowserUpdate ( ) ;
2011-06-26 15:10:13 +00:00
}
}
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
void CMenus : : ConchainFavoritesUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
2010-07-04 14:10:00 +00:00
{
2011-08-13 00:11:06 +00:00
pfnCallback ( pResult , pCallbackUserData ) ;
2023-09-07 19:26:40 +00:00
if ( pResult - > NumArguments ( ) > = 1 & & g_Config . m_UiPage = = PAGE_FAVORITES )
2010-07-04 14:10:00 +00:00
( ( CMenus * ) pUserData ) - > ServerBrowser ( ) - > Refresh ( IServerBrowser : : TYPE_FAVORITES ) ;
}
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
void CMenus : : ConchainCommunitiesUpdate ( IConsole : : IResult * pResult , void * pUserData , IConsole : : FCommandCallback pfnCallback , void * pCallbackUserData )
{
pfnCallback ( pResult , pCallbackUserData ) ;
if ( pResult - > NumArguments ( ) > = 1 & & ( g_Config . m_UiPage = = PAGE_INTERNET | | g_Config . m_UiPage = = PAGE_FAVORITES ) )
( ( CMenus * ) pUserData ) - > UpdateCommunityCache ( true ) ;
}
void CMenus : : UpdateCommunityCache ( bool Force )
{
const bool PageWithCommunities = g_Config . m_UiPage = = PAGE_INTERNET | | g_Config . m_UiPage = = PAGE_FAVORITES ;
if ( ! Force & & m_CommunityCache . m_UpdateTime ! = 0 & & m_CommunityCache . m_UpdateTime = = ServerBrowser ( ) - > DDNetInfoUpdateTime ( ) & & m_CommunityCache . m_PageWithCommunities = = PageWithCommunities )
return ;
m_CommunityCache . m_UpdateTime = ServerBrowser ( ) - > DDNetInfoUpdateTime ( ) ;
m_CommunityCache . m_PageWithCommunities = PageWithCommunities ;
if ( m_CommunityCache . m_PageWithCommunities )
m_CommunityCache . m_vpSelectedCommunities = ServerBrowser ( ) - > SelectedCommunities ( ) ;
else
m_CommunityCache . m_vpSelectedCommunities . clear ( ) ;
m_CommunityCache . m_vpSelectableCountries . clear ( ) ;
m_CommunityCache . m_vpSelectableTypes . clear ( ) ;
for ( const CCommunity * pCommunity : m_CommunityCache . m_vpSelectedCommunities )
{
for ( const auto & Country : pCommunity - > Countries ( ) )
{
const auto ExistingCountry = std : : find_if ( m_CommunityCache . m_vpSelectableCountries . begin ( ) , m_CommunityCache . m_vpSelectableCountries . end ( ) , [ & ] ( const CCommunityCountry * pOther ) {
return str_comp ( Country . Name ( ) , pOther - > Name ( ) ) = = 0 & & Country . FlagId ( ) = = pOther - > FlagId ( ) ;
} ) ;
if ( ExistingCountry = = m_CommunityCache . m_vpSelectableCountries . end ( ) )
{
m_CommunityCache . m_vpSelectableCountries . push_back ( & Country ) ;
}
}
for ( const auto & Type : pCommunity - > Types ( ) )
{
const auto ExistingType = std : : find_if ( m_CommunityCache . m_vpSelectableTypes . begin ( ) , m_CommunityCache . m_vpSelectableTypes . end ( ) , [ & ] ( const CCommunityType * pOther ) {
return str_comp ( Type . Name ( ) , pOther - > Name ( ) ) = = 0 ;
} ) ;
if ( ExistingType = = m_CommunityCache . m_vpSelectableTypes . end ( ) )
{
m_CommunityCache . m_vpSelectableTypes . push_back ( & Type ) ;
}
}
}
m_CommunityCache . m_AnyRanksAvailable = std : : any_of ( m_CommunityCache . m_vpSelectedCommunities . begin ( ) , m_CommunityCache . m_vpSelectedCommunities . end ( ) , [ ] ( const CCommunity * pCommunity ) {
return pCommunity - > HasRanks ( ) ;
} ) ;
}
CMenus : : CAbstractCommunityIconJob : : CAbstractCommunityIconJob ( CMenus * pMenus , const char * pCommunityId , int StorageType ) :
m_pMenus ( pMenus ) ,
m_StorageType ( StorageType )
{
str_copy ( m_aCommunityId , pCommunityId ) ;
str_format ( m_aPath , sizeof ( m_aPath ) , " communityicons/%s.png " , pCommunityId ) ;
}
2023-11-16 20:33:10 +00:00
CMenus : : CAbstractCommunityIconJob : : ~ CAbstractCommunityIconJob ( )
{
free ( m_ImageInfo . m_pData ) ;
m_ImageInfo . m_pData = nullptr ;
}
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
int CMenus : : CCommunityIconDownloadJob : : OnCompletion ( int State )
{
State = CHttpRequest : : OnCompletion ( State ) ;
if ( State = = HTTP_DONE )
{
if ( m_pMenus - > LoadCommunityIconFile ( Dest ( ) , IStorage : : TYPE_SAVE , m_ImageInfo , m_Sha256 ) )
m_Success = true ;
else
State = HTTP_ERROR ;
}
return State ;
}
CMenus : : CCommunityIconDownloadJob : : CCommunityIconDownloadJob ( CMenus * pMenus , const char * pCommunityId , const char * pUrl ) :
CHttpRequest ( pUrl ) ,
CAbstractCommunityIconJob ( pMenus , pCommunityId , IStorage : : TYPE_SAVE )
{
WriteToFile ( pMenus - > Storage ( ) , m_aPath , IStorage : : TYPE_SAVE ) ;
Timeout ( CTimeout { 0 , 0 , 0 , 0 } ) ;
LogProgress ( HTTPLOG : : FAILURE ) ;
}
void CMenus : : CCommunityIconLoadJob : : Run ( )
{
m_Success = m_pMenus - > LoadCommunityIconFile ( m_aPath , m_StorageType , m_ImageInfo , m_Sha256 ) ;
}
CMenus : : CCommunityIconLoadJob : : CCommunityIconLoadJob ( CMenus * pMenus , const char * pCommunityId , int StorageType ) :
CAbstractCommunityIconJob ( pMenus , pCommunityId , StorageType )
{
}
int CMenus : : CommunityIconScan ( const char * pName , int IsDir , int DirType , void * pUser )
{
const char * pExtension = " .png " ;
CMenus * pSelf = static_cast < CMenus * > ( pUser ) ;
if ( IsDir | | ! str_endswith ( pName , pExtension ) | | str_length ( pName ) - str_length ( pExtension ) > = ( int ) CServerInfo : : MAX_COMMUNITY_ID_LENGTH )
return 0 ;
char aCommunityId [ CServerInfo : : MAX_COMMUNITY_ID_LENGTH ] ;
str_truncate ( aCommunityId , sizeof ( aCommunityId ) , pName , str_length ( pName ) - str_length ( pExtension ) ) ;
std : : shared_ptr < CCommunityIconLoadJob > pJob = std : : make_shared < CCommunityIconLoadJob > ( pSelf , aCommunityId , DirType ) ;
pSelf - > Engine ( ) - > AddJob ( pJob ) ;
pSelf - > m_CommunityIconLoadJobs . push_back ( pJob ) ;
return 0 ;
}
const CMenus : : SCommunityIcon * CMenus : : FindCommunityIcon ( const char * pCommunityId )
{
auto Icon = std : : find_if ( m_vCommunityIcons . begin ( ) , m_vCommunityIcons . end ( ) , [ pCommunityId ] ( const SCommunityIcon & Element ) {
return str_comp ( Element . m_aCommunityId , pCommunityId ) = = 0 ;
} ) ;
return Icon = = m_vCommunityIcons . end ( ) ? nullptr : & ( * Icon ) ;
}
bool CMenus : : LoadCommunityIconFile ( const char * pPath , int DirType , CImageInfo & Info , SHA256_DIGEST & Sha256 )
{
char aError [ IO_MAX_PATH_LENGTH + 128 ] ;
if ( ! Graphics ( ) - > LoadPNG ( & Info , pPath , DirType ) )
{
str_format ( aError , sizeof ( aError ) , " Failed to load community icon from '%s' " , pPath ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " menus/browser " , aError ) ;
return false ;
}
if ( Info . m_Format ! = CImageInfo : : FORMAT_RGBA )
{
Graphics ( ) - > FreePNG ( & Info ) ;
str_format ( aError , sizeof ( aError ) , " Failed to load community icon from '%s': must be an RGBA image " , pPath ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " menus/browser " , aError ) ;
return false ;
}
if ( ! Storage ( ) - > CalculateHashes ( pPath , DirType , & Sha256 ) )
{
Graphics ( ) - > FreePNG ( & Info ) ;
str_format ( aError , sizeof ( aError ) , " Failed to load community icon from '%s': could not calculate hash " , pPath ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_ADDINFO , " menus/browser " , aError ) ;
return false ;
}
return true ;
}
void CMenus : : LoadCommunityIconFinish ( const char * pCommunityId , CImageInfo & & Info , SHA256_DIGEST & & Sha256 )
{
SCommunityIcon CommunityIcon ;
str_copy ( CommunityIcon . m_aCommunityId , pCommunityId ) ;
CommunityIcon . m_Sha256 = Sha256 ;
CommunityIcon . m_OrgTexture = Graphics ( ) - > LoadTextureRaw ( Info . m_Width , Info . m_Height , Info . m_Format , Info . m_pData , 0 ) ;
// create gray scale version
unsigned char * pData = static_cast < unsigned char * > ( Info . m_pData ) ;
const size_t Step = Info . PixelSize ( ) ;
for ( int i = 0 ; i < Info . m_Width * Info . m_Height ; i + + )
{
int v = ( pData [ i * Step ] + pData [ i * Step + 1 ] + pData [ i * Step + 2 ] ) / 3 ;
pData [ i * Step ] = v ;
pData [ i * Step + 1 ] = v ;
pData [ i * Step + 2 ] = v ;
}
CommunityIcon . m_GreyTexture = Graphics ( ) - > LoadTextureRaw ( Info . m_Width , Info . m_Height , Info . m_Format , Info . m_pData , 0 ) ;
Graphics ( ) - > FreePNG ( & Info ) ;
auto ExistingIcon = std : : find_if ( m_vCommunityIcons . begin ( ) , m_vCommunityIcons . end ( ) , [ pCommunityId ] ( const SCommunityIcon & Element ) {
return str_comp ( Element . m_aCommunityId , pCommunityId ) = = 0 ;
} ) ;
if ( ExistingIcon = = m_vCommunityIcons . end ( ) )
{
m_vCommunityIcons . push_back ( CommunityIcon ) ;
}
else
{
Graphics ( ) - > UnloadTexture ( & ExistingIcon - > m_OrgTexture ) ;
Graphics ( ) - > UnloadTexture ( & ExistingIcon - > m_GreyTexture ) ;
* ExistingIcon = CommunityIcon ;
}
char aBuf [ CServerInfo : : MAX_COMMUNITY_ID_LENGTH + 32 ] ;
str_format ( aBuf , sizeof ( aBuf ) , " Loaded community icon '%s' " , pCommunityId ) ;
Console ( ) - > Print ( IConsole : : OUTPUT_LEVEL_DEBUG , " menus/browser " , aBuf ) ;
}
void CMenus : : RenderCommunityIcon ( const SCommunityIcon * pIcon , CUIRect Rect , bool Active )
{
Rect . VMargin ( Rect . w / 2.0f - Rect . h , & Rect ) ;
Graphics ( ) - > TextureSet ( Active ? pIcon - > m_OrgTexture : pIcon - > m_GreyTexture ) ;
Graphics ( ) - > QuadsBegin ( ) ;
Graphics ( ) - > SetColor ( 1.0f , 1.0f , 1.0f , Active ? 1.0f : 0.5f ) ;
IGraphics : : CQuadItem QuadItem ( Rect . x , Rect . y , Rect . w , Rect . h ) ;
Graphics ( ) - > QuadsDrawTL ( & QuadItem , 1 ) ;
Graphics ( ) - > QuadsEnd ( ) ;
}
void CMenus : : UpdateCommunityIcons ( )
{
// Update load jobs (icon is loaded from existing file)
if ( ! m_CommunityIconLoadJobs . empty ( ) )
{
std : : shared_ptr < CCommunityIconLoadJob > pJob = m_CommunityIconLoadJobs . front ( ) ;
if ( pJob - > Status ( ) = = IJob : : STATE_DONE )
{
if ( pJob - > Success ( ) )
LoadCommunityIconFinish ( pJob - > CommunityId ( ) , pJob - > ImageInfo ( ) , pJob - > Sha256 ( ) ) ;
m_CommunityIconLoadJobs . pop_front ( ) ;
}
// Don't start download jobs until all load jobs are done
if ( ! m_CommunityIconLoadJobs . empty ( ) )
return ;
}
// Update download jobs (icon is downloaded and loaded from new file)
if ( ! m_CommunityIconDownloadJobs . empty ( ) )
{
std : : shared_ptr < CCommunityIconDownloadJob > pJob = m_CommunityIconDownloadJobs . front ( ) ;
if ( pJob - > Status ( ) = = IJob : : STATE_DONE )
{
if ( pJob - > Success ( ) )
LoadCommunityIconFinish ( pJob - > CommunityId ( ) , pJob - > ImageInfo ( ) , pJob - > Sha256 ( ) ) ;
m_CommunityIconDownloadJobs . pop_front ( ) ;
}
}
// Rescan for changed communities only when necessary
if ( m_CommunityIconsUpdateTime ! = 0 & & m_CommunityIconsUpdateTime = = ServerBrowser ( ) - > DDNetInfoUpdateTime ( ) )
return ;
m_CommunityIconsUpdateTime = ServerBrowser ( ) - > DDNetInfoUpdateTime ( ) ;
// Remove icons for removed communities
auto RemovalIterator = m_vCommunityIcons . begin ( ) ;
while ( RemovalIterator ! = m_vCommunityIcons . end ( ) )
{
if ( ServerBrowser ( ) - > Community ( RemovalIterator - > m_aCommunityId ) = = nullptr )
{
Graphics ( ) - > UnloadTexture ( & RemovalIterator - > m_OrgTexture ) ;
Graphics ( ) - > UnloadTexture ( & RemovalIterator - > m_GreyTexture ) ;
RemovalIterator = m_vCommunityIcons . erase ( RemovalIterator ) ;
}
else
{
+ + RemovalIterator ;
}
}
// Find added and updated community icons
for ( const auto & Community : ServerBrowser ( ) - > Communities ( ) )
{
if ( str_comp ( Community . Id ( ) , IServerBrowser : : COMMUNITY_NONE ) = = 0 )
continue ;
auto ExistingIcon = std : : find_if ( m_vCommunityIcons . begin ( ) , m_vCommunityIcons . end ( ) , [ Community ] ( const auto & Element ) {
return str_comp ( Element . m_aCommunityId , Community . Id ( ) ) = = 0 ;
} ) ;
auto pExistingDownload = std : : find_if ( m_CommunityIconDownloadJobs . begin ( ) , m_CommunityIconDownloadJobs . end ( ) , [ Community ] ( const auto & Element ) {
return str_comp ( Element - > CommunityId ( ) , Community . Id ( ) ) = = 0 ;
} ) ;
if ( pExistingDownload = = m_CommunityIconDownloadJobs . end ( ) & & ( ExistingIcon = = m_vCommunityIcons . end ( ) | | ExistingIcon - > m_Sha256 ! = Community . IconSha256 ( ) ) )
{
Add icon URL, remove `servers-key`/`ranks-key` from community JSON
Previously:
```json
{
"ddnet": {
"name": "DDraceNetwork",
"servers-key": "servers",
"ranks-key": "maps",
"icon-sha256": "162313eeb954e34495ad03066fee1418ed3c963e76cc83dff993e1c7856c742b"
}
}
```
Now:
```json
[
{
"id": "ddnet",
"name": "DDraceNetwork",
"icon": {
"sha256": "162313eeb954e34495ad03066fee1418ed3c963e76cc83dff993e1c7856c742b",
"url": "https://info.ddnet.org/icons/ddnet.png"
},
"ranks": [
…
],
"servers": {
…
}
}
]
```
Special case `ddnet` to look for the `servers`, `maps` in the top-level
and `kog` to look for `servers-kog` in the top-level.
2023-11-18 20:52:51 +00:00
std : : shared_ptr < CCommunityIconDownloadJob > pJob = std : : make_shared < CCommunityIconDownloadJob > ( this , Community . Id ( ) , Community . IconUrl ( ) ) ;
Add community server filter and icons, remove DDNet and KoG tabs
Remove the DDNet and KoG tabs and replace them with a community filter, which works like the country and type filters. Community information (ID, name, icon SHA256, countries, types, servers, ranked maps) is loaded dynamically from the DDNet info json.
The official checkmark icon is replaced with community icons. The icons are downloaded to the `communityicons` folder in the config directory from a URL specified in the DDNet info json. The icons are only re-downloaded when their SHA256 has changed.
Per default, the Internet tab with all communities is selected. When starting the client for the first time, only the DDNet community is selected. The community, country and type filters can also be used on the Favorites tab now. The LAN tab remains unchanged.
The country and type filters are refactored. Previously, using these filters changed the total number of servers and players that were displayed, as the filter was implemented as a separate step. Now the community, country and type filters work like the other browser filters. This also has the benefit that the server list and DDNet info json are not reloaded each time these filters are changed, as updating the local filtering/sorting is enough now.
The check for finished maps is made more efficient by using an `std::unordered_set` instead of linear search.
Closes #5654.
2023-08-28 20:08:51 +00:00
Engine ( ) - > AddJob ( pJob ) ;
m_CommunityIconDownloadJobs . push_back ( pJob ) ;
}
}
}