Ticket #2405: colist_handler_lobby_sortable_game_and_player_list.patch
File colist_handler_lobby_sortable_game_and_player_list.patch, 10.3 KB (added by , 9 years ago) |
---|
-
binaries/data/mods/public/gui/lobby/lobby.js
1 1 var g_ChatMessages = []; 2 2 var g_Name = "unknown"; 3 3 var g_GameList = {}; 4 var g_GameListSortBy = "default"; 5 var g_PlayerListSortBy = "default"; 6 var g_GameListOrder = 1; // 1 for ascending sort, and -1 for descending 7 var g_PlayerListOrder = 1; 4 8 var g_specialKey = Math.random(); 5 9 // This object looks like {"name":[numMessagesSinceReset, lastReset, timeBlocked]} when in use. 6 10 var g_spamMonitor = {}; 7 11 var g_timestamp = Engine.ConfigDB_GetValue("user", "lobby.chattimestamp") == "true"; 8 12 var g_mapSizes = {}; … … 71 75 72 76 //////////////////////////////////////////////////////////////////////////////////////////////// 73 77 // Update functions 74 78 //////////////////////////////////////////////////////////////////////////////////////////////// 75 79 80 function updateGameListOrderSelection() 81 { 82 var orderBy = Engine.GetGUIObjectByName("gamesBox").selected_column; 83 84 // If selected column equal to previous then just reverse order 85 if (orderBy == g_GameListSortBy) 86 g_GameListOrder = -g_GameListOrder; 87 else 88 { 89 g_GameListSortBy = orderBy; 90 g_GameListOrder = 1; 91 } 92 93 applyFilters(); 94 } 95 96 function updatePlayerListOrderSelection() { 97 var orderBy = Engine.GetGUIObjectByName("playersBox").selected_column; 98 99 // If selected column equal to previous then just reverse order 100 if (orderBy == g_PlayerListSortBy) 101 g_PlayerListOrder = -g_PlayerListOrder; 102 else 103 { 104 g_PlayerListSortBy = orderBy; 105 g_PlayerListOrder = 1; 106 } 107 updatePlayerList(); 108 } 109 76 110 function resetFilters() 77 111 { 78 112 // Reset states of gui objects 79 113 Engine.GetGUIObjectByName("mapSizeFilter").selected = 0 80 114 Engine.GetGUIObjectByName("playersNumberFilter").selected = 0; 81 115 Engine.GetGUIObjectByName("mapTypeFilter").selected = 0; 82 116 Engine.GetGUIObjectByName("showFullFilter").checked = false; 83 117 84 // Update the list of games 85 updateGameList(); 86 87 // Update info box about the game currently selected 88 updateGameSelection(); 118 applyFilters(); 89 119 } 90 120 91 121 function applyFilters() 92 122 { 93 123 // Update the list of games … … 146 176 logo.size = "50%-110 40 50%+110 140"; 147 177 } 148 178 } 149 179 150 180 /** 151 * Do a full update of the player listing, including ratings from C++.181 * Do a full update of the player listing, including ratings from cached C++ information. 152 182 * 153 183 * @return Array containing the player, presence, nickname, and rating listings. 154 184 */ 155 185 function updatePlayerList() 156 186 { … … 161 191 var ratingList = []; 162 192 var cleanPlayerList = Engine.GetPlayerList(); 163 193 // Sort the player list, ignoring case. 164 194 cleanPlayerList.sort(function(a,b) 165 195 { 166 var aName = a.name.toLowerCase(); 167 var bName = b.name.toLowerCase(); 168 return ((aName > bName) ? 1 : (bName > aName) ? -1 : 0); 169 } ); 196 switch (g_PlayerListSortBy) 197 { 198 case 'rating': 199 if (a.rating < b.rating) 200 return -g_PlayerListOrder; 201 else if (a.rating > b.rating) 202 return g_PlayerListOrder; 203 return 0; 204 case 'status': 205 let order = ["available", "away", "playing", "gone", "offline"]; 206 let presenceA = order.indexOf(a.presence); 207 let presenceB = order.indexOf(b.presence); 208 if (presenceA < presenceB) 209 return -g_PlayerListOrder; 210 else if (presenceA > presenceB) 211 return g_PlayerListOrder; 212 return 0; 213 default: 214 var aName = a.name.toLowerCase(); 215 var bName = b.name.toLowerCase(); 216 if (aName < bName) 217 return -g_PlayerListOrder; 218 else if (aName > bName) 219 return g_PlayerListOrder; 220 return 0; 221 } 222 }); 170 223 for (var i = 0; i < cleanPlayerList.length; i++) 171 224 { 172 225 // Identify current user's rating. 173 226 if (cleanPlayerList[i].name == g_Name && cleanPlayerList[i].rating) 174 227 g_userRating = cleanPlayerList[i].rating; … … 362 415 g_GameList = gameList; 363 416 364 417 // Sort the list of games to that games 'waiting' are displayed at the top, followed by 'init', followed by 'running'. 365 418 var gameStatuses = ['waiting', 'init', 'running']; 366 419 g_GameList.sort(function (a,b) { 367 if (gameStatuses.indexOf(a.state) < gameStatuses.indexOf(b.state)) 368 return -1; 369 else if (gameStatuses.indexOf(a.state) > gameStatuses.indexOf(b.state)) 370 return 1; 371 372 // Alphabetical comparison of names as tiebreaker. 373 if (a.name < b.name) 374 return -1; 375 else if (a.name > b.name) 376 return 1; 377 return 0; 420 switch (g_GameListSortBy) 421 { 422 case 'name': 423 if (a.name < b.name) 424 return -g_GameListOrder; 425 else if (a.name > b.name) 426 return g_GameListOrder; 427 return 0; 428 case 'mapName': 429 if (translate(a.niceMapName) < translate(b.niceMapName)) 430 return -g_GameListOrder; 431 else if (translate(a.niceMapName) > translate(b.niceMapName)) 432 return g_GameListOrder; 433 return 0; 434 case 'mapSize': 435 // mapSize contains the number of tiles for random maps 436 // scenario maps always display default size 437 if (a.mapSize < b.mapSize) 438 return -g_GameListOrder; 439 else if (a.mapSize > b.mapSize) 440 return g_GameListOrder; 441 return 0; 442 case 'mapType': 443 if (a.mapType < b.mapType) 444 return -g_GameListOrder; 445 else if (a.mapType > b.mapType) 446 return g_GameListOrder; 447 return 0; 448 case 'nPlayers': 449 // Numerical comparison of player count ratio. 450 if (a.nbp * b.tnbp < b.nbp * a.tnbp) // ratio a = a.nbp / a.tnbp, ratio b = b.nbp / b.tnbp 451 return -g_GameListOrder; 452 else if (a.nbp * b.tnbp > b.nbp * a.tnbp) 453 return g_GameListOrder; 454 return 0; 455 default: 456 if (gameStatuses.indexOf(a.state) < gameStatuses.indexOf(b.state)) 457 return -1; 458 else if (gameStatuses.indexOf(a.state) > gameStatuses.indexOf(b.state)) 459 return 1; 460 461 // Alphabetical comparison of names as tiebreaker. 462 if (a.name < b.name) 463 return -1; 464 else if (a.name > b.name) 465 return 1; 466 return 0; 467 } 378 468 }); 379 469 380 470 var list_name = []; 381 471 var list_ip = []; 382 472 var list_mapName = []; -
binaries/data/mods/public/gui/lobby/lobby.xml
18 18 onTick(); 19 19 </action> 20 20 21 21 <!-- Left panel: Player list. --> 22 22 <object name="leftPanel" size="20 30 20% 100%-280"> 23 <object name="playersBox" style="ModernList" type="olist" s ize="0 0 100% 100%" font="sans-bold-stroke-13">23 <object name="playersBox" style="ModernList" type="olist" sortable="true" size="0 0 100% 100%" font="sans-bold-stroke-13"> 24 24 <def id="status" width="26%"> 25 25 <translatableAttribute id="heading">Status</translatableAttribute> 26 26 </def> 27 27 <def id="name" width="50%"> 28 28 <translatableAttribute id="heading">Name</translatableAttribute> … … 31 31 <translatableAttribute id="heading">Rating</translatableAttribute> 32 32 </def> 33 33 <action on="SelectionChange"> 34 34 displayProfile("lobbylist"); 35 35 </action> 36 <action on="SelectionColumnChange"> 37 updatePlayerListOrderSelection(); 38 </action> 36 39 </object> 37 40 </object> 38 41 39 42 <object name="profilePanel" size="20 100%-275 20% 100%-80"> 40 43 <object name="profileBox" type="image" sprite="ModernDarkBoxGold" size="0 0 100% 100%"> … … 167 170 </object> 168 171 </object> 169 172 170 173 <!-- Middle panel: Filters, game list, chat box. --> 171 174 <object name="middlePanel" size="20%+5 5% 100%-255 97.2%"> 172 <object name="gamesBox" style="ModernList" type="olist" s ize="0 25 100% 48%" font="sans-stroke-13">175 <object name="gamesBox" style="ModernList" type="olist" sortable="true" size="0 25 100% 48%" font="sans-stroke-13"> 173 176 <action on="SelectionChange">updateGameSelection();</action> 177 <action on="SelectionColumnChange">updateGameListOrderSelection();</action> 174 178 <def id="name" color="0 60 0" width="27%"> 175 179 <translatableAttribute id="heading">Name</translatableAttribute> 176 180 </def> 177 181 <!--<def id="ip" heading="IP" color="0 128 128" width="170"/>--> 178 182 <def id="mapName" color="128 128 128" width="25%"> -
source/gui/COList.cpp
17 17 #include "precompiled.h" 18 18 #include "COList.h" 19 19 #include "i18n/L10n.h" 20 20 21 21 #include "ps/CLogger.h" 22 #include "soundmanager/ISoundManager.h" 22 23 23 24 COList::COList() : CList(),m_HeadingHeight(30.f) 24 25 { 25 26 AddSetting(GUIST_CGUISpriteInstance, "sprite_heading"); 27 AddSetting(GUIST_bool, "sortable"); // The actual sorting is done in JS for more versatility 28 AddSetting(GUIST_CStr, "selected_column"); 29 AddSetting(GUIST_int, "selected_def"); 30 31 // Nothing is selected by default. 32 GUI<CStr>::SetSetting(this, "selected_column", ""); 33 GUI<int>::SetSetting(this, "selected_def", -1); 26 34 } 27 35 28 36 void COList::SetupText() 29 37 { 30 38 if (!GetGUI()) … … 117 125 } 118 126 119 127 void COList::HandleMessage(SGUIMessage &Message) 120 128 { 121 129 CList::HandleMessage(Message); 130 131 switch (Message.type) 132 { 133 // If somebody clicks on the column heading 134 case GUIM_MOUSE_PRESS_LEFT: 135 { 136 bool sortable; 137 GUI<bool>::GetSetting(this, "sortable", sortable); 138 if (!sortable) 139 return; 140 141 CPos mouse = GetMousePos(); 142 if (!m_CachedActualSize.PointInside(mouse)) 143 return; 144 145 float xpos = 0; 146 for (unsigned int def = 0; def < m_ObjectsDefs.size(); ++def) 147 { 148 float width = m_ObjectsDefs[def].m_Width; 149 // Check if it's a decimal value, and if so, assume relative positioning. 150 if (m_ObjectsDefs[def].m_Width < 1 && m_ObjectsDefs[def].m_Width > 0) 151 width *= m_TotalAvalibleColumnWidth; 152 CPos leftTopCorner = m_CachedActualSize.TopLeft() + CPos(xpos, 4); 153 if (mouse.x >= leftTopCorner.x && 154 mouse.x < leftTopCorner.x + width && 155 mouse.y < leftTopCorner.y + m_HeadingHeight) 156 { 157 GUI<CStr>::SetSetting(this, "selected_column", m_ObjectsDefs[def].m_Id.substr(5)); 158 GUI<int>::SetSetting(this, "selected_def", def); 159 ScriptEvent("selectioncolumnchange"); 160 161 CStrW soundPath; 162 if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_selected", soundPath) == PSRETURN_OK && !soundPath.empty()) 163 g_SoundManager->PlayAsUI(soundPath.c_str(), false); 164 165 return; 166 } 167 xpos += width; 168 } 169 return; 170 } 171 default: 172 return; 173 } 122 174 } 123 175 124 176 bool COList::HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile) 125 177 { 126 178 #define ELMT(x) int elmt_##x = pFile->GetElementID(#x)