Ticket #2405: colist_handler_lobby_sortable_game_and_player_list_with_arrows_v4.patch
File colist_handler_lobby_sortable_game_and_player_list_with_arrows_v4.patch, 18.9 KB (added by , 9 years ago) |
---|
-
binaries/data/mods/mod/art/textures/ui/global/modern/arrow-down.png
Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
-
binaries/data/mods/mod/art/textures/ui/global/modern/arrow-up.png
Property changes on: binaries/data/mods/mod/art/textures/ui/global/modern/arrow-down.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
-
binaries/data/mods/mod/art/textures/ui/global/modern/arrows-up-down.png
Property changes on: binaries/data/mods/mod/art/textures/ui/global/modern/arrow-up.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
-
binaries/data/mods/mod/art/textures/ui/global/modern/dropup-arrow.png
Property changes on: binaries/data/mods/mod/art/textures/ui/global/modern/arrows-up-down.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
-
binaries/data/mods/mod/gui/common/modern/sprites.xml
Property changes on: binaries/data/mods/mod/art/textures/ui/global/modern/dropup-arrow.png ___________________________________________________________________ Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property
585 585 size="0 6 16 22" 586 586 /> 587 587 </sprite> 588 <sprite name = "ModernDropUpArrow"> 589 <image texture = "global/modern/dropup-arrow.png" 590 real_texture_placement = "0 0 16 16" 591 texture_size="0 0 16 16" 592 size="0 6 16 22" 593 /> 594 </sprite> 595 <sprite name = "ModernNotSorted"> 596 <image texture = "global/modern/arrows-up-down.png" 597 real_texture_placement = "0 0 16 16" 598 texture_size="0 0 16 16" 599 size="0 6 16 22" 600 /> 601 </sprite> 602 <sprite name = "ModernArrowUp"> 603 <image texture = "global/modern/arrow-up.png" 604 real_texture_placement = "0 0 16 16" 605 texture_size="0 0 16 16" 606 size="0 6 16 22" 607 /> 608 </sprite> 609 <sprite name = "ModernArrowDown"> 610 <image texture = "global/modern/arrow-down.png" 611 real_texture_placement = "0 0 16 16" 612 texture_size="0 0 16 16" 613 size="0 6 16 22" 614 /> 615 </sprite> 588 616 <sprite name = "ModernDropDownArrowHighlight"> 589 617 <image texture = "global/modern/dropdown-arrow.png" 590 618 real_texture_placement = "0 0 16 16" -
binaries/data/mods/public/gui/gui.rnc
70 70 attribute scrollbar { bool }?& 71 71 attribute scrollbar_style { text }?& 72 72 attribute scroll_bottom { bool }?& 73 attribute sortable { bool }?& 73 74 attribute sound_closed { text }?& 74 75 attribute sound_disabled { text }?& 75 76 attribute sound_enter { text }?& … … 79 80 attribute sound_selected { text }?& 80 81 attribute sprite { text }?& 81 82 attribute sprite2 { text }?& 83 attribute sprite_asc { text }?& 82 84 attribute sprite_heading { text }?& 83 85 attribute sprite_bar { text }?& 84 86 attribute sprite_background { text }?& 87 attribute sprite_desc { text }?& 85 88 attribute sprite_disabled { text }?& 86 89 attribute sprite_list { text }?& 87 90 attribute sprite2_disabled { text }?& 91 attribute sprite_not_sorted { text }?& 88 92 attribute sprite_over { text }?& 89 93 attribute sprite2_over { text }?& 90 94 attribute sprite_pressed { text }?& -
binaries/data/mods/public/gui/gui.rng
287 287 </attribute> 288 288 </optional> 289 289 <optional> 290 <attribute name="sortable"/> 291 </optional> 292 <optional> 290 293 <attribute name="sound_closed"/> 291 294 </optional> 292 295 <optional> … … 347 350 <attribute name="sprite_selectarea"/> 348 351 </optional> 349 352 <optional> 353 <attribute name="sprite_asc"/> 354 </optional> 355 <optional> 356 <attribute name="sprite_desc"/> 357 </optional> 358 <optional> 359 <attribute name="sprite_not_sorted"/> 360 </optional> 361 <optional> 350 362 <attribute name="square_side"> 351 363 <data type="decimal"/> 352 364 </attribute> -
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 = "name"; 5 var g_PlayerListSortBy = "name"; 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 = {}; … … 74 78 // Update functions 75 79 //////////////////////////////////////////////////////////////////////////////////////////////// 76 80 81 function updateGameListOrderSelection() 82 { 83 g_GameListSortBy = Engine.GetGUIObjectByName("gamesBox").selected_column; 84 g_GameListOrder = Engine.GetGUIObjectByName("gamesBox").selected_column_order; 85 86 applyFilters(); 87 } 88 89 function updatePlayerListOrderSelection() 90 { 91 g_PlayerListSortBy = Engine.GetGUIObjectByName("playersBox").selected_column; 92 g_PlayerListOrder = Engine.GetGUIObjectByName("playersBox").selected_column_order; 93 94 updatePlayerList(); 95 } 96 77 97 function resetFilters() 78 98 { 79 99 // Reset states of gui objects … … 82 102 Engine.GetGUIObjectByName("mapTypeFilter").selected = 0; 83 103 Engine.GetGUIObjectByName("showFullFilter").checked = false; 84 104 85 // Update the list of games 86 updateGameList(); 87 88 // Update info box about the game currently selected 89 updateGameSelection(); 105 applyFilters(); 90 106 } 91 107 92 108 function applyFilters() … … 149 165 } 150 166 151 167 /** 152 * Do a full update of the player listing, including ratings from C++.168 * Do a full update of the player listing, including ratings from cached C++ information. 153 169 * 154 170 * @return Array containing the player, presence, nickname, and rating listings. 155 171 */ … … 164 180 // Sort the player list, ignoring case. 165 181 cleanPlayerList.sort(function(a,b) 166 182 { 167 var aName = a.name.toLowerCase(); 168 var bName = b.name.toLowerCase(); 169 return ((aName > bName) ? 1 : (bName > aName) ? -1 : 0); 170 } ); 183 switch (g_PlayerListSortBy) 184 { 185 case 'rating': 186 if (a.rating < b.rating) 187 return -g_PlayerListOrder; 188 else if (a.rating > b.rating) 189 return g_PlayerListOrder; 190 return 0; 191 case 'status': 192 let order = ["available", "away", "playing", "gone", "offline"]; 193 let presenceA = order.indexOf(a.presence); 194 let presenceB = order.indexOf(b.presence); 195 if (presenceA < presenceB) 196 return -g_PlayerListOrder; 197 else if (presenceA > presenceB) 198 return g_PlayerListOrder; 199 return 0; 200 default: 201 var aName = a.name.toLowerCase(); 202 var bName = b.name.toLowerCase(); 203 if (aName < bName) 204 return -g_PlayerListOrder; 205 else if (aName > bName) 206 return g_PlayerListOrder; 207 return 0; 208 } 209 }); 171 210 for (var i = 0; i < cleanPlayerList.length; i++) 172 211 { 173 212 // Identify current user's rating. … … 365 404 // Sort the list of games to that games 'waiting' are displayed at the top, followed by 'init', followed by 'running'. 366 405 var gameStatuses = ['waiting', 'init', 'running']; 367 406 g_GameList.sort(function (a,b) { 368 if (gameStatuses.indexOf(a.state) < gameStatuses.indexOf(b.state)) 369 return -1; 370 else if (gameStatuses.indexOf(a.state) > gameStatuses.indexOf(b.state)) 371 return 1; 407 switch (g_GameListSortBy) 408 { 409 case 'name': 410 case 'mapSize': 411 // mapSize contains the number of tiles for random maps 412 // scenario maps always display default size 413 case 'mapType': 414 if (a[g_GameListSortBy] < b[g_GameListSortBy]) 415 return -g_GameListOrder; 416 else if (a[g_GameListSortBy] > b[g_GameListSortBy]) 417 return g_GameListOrder; 418 return 0; 419 case 'mapName': 420 if (translate(a.niceMapName) < translate(b.niceMapName)) 421 return -g_GameListOrder; 422 else if (translate(a.niceMapName) > translate(b.niceMapName)) 423 return g_GameListOrder; 424 return 0; 425 case 'nPlayers': 426 // Numerical comparison of player count ratio. 427 if (a.nbp * b.tnbp < b.nbp * a.tnbp) // ratio a = a.nbp / a.tnbp, ratio b = b.nbp / b.tnbp 428 return -g_GameListOrder; 429 else if (a.nbp * b.tnbp > b.nbp * a.tnbp) 430 return g_GameListOrder; 431 return 0; 432 default: 433 if (gameStatuses.indexOf(a.state) < gameStatuses.indexOf(b.state)) 434 return -1; 435 else if (gameStatuses.indexOf(a.state) > gameStatuses.indexOf(b.state)) 436 return 1; 372 437 373 // Alphabetical comparison of names as tiebreaker. 374 if (a.name < b.name) 375 return -1; 376 else if (a.name > b.name) 377 return 1; 378 return 0; 438 // Alphabetical comparison of names as tiebreaker. 439 if (a.name < b.name) 440 return -1; 441 else if (a.name > b.name) 442 return 1; 443 return 0; 444 } 379 445 }); 380 446 381 447 var list_name = []; -
binaries/data/mods/public/gui/lobby/lobby.xml
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" size="0 0 100% 100%" font="sans-bold-stroke-13">23 <object name="playersBox" style="ModernList" sprite_asc="ModernArrowDown" default_column="name" sprite_desc="ModernArrowUp" sprite_not_sorted="ModernNotSorted" 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 <def id="name" width=" 50%">27 <def id="name" width="48%"> 28 28 <translatableAttribute id="heading">Name</translatableAttribute> 29 29 </def> 30 <def id="rating" width="2 4%">30 <def id="rating" width="26%"> 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 … … 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" size="0 25 100% 48%" font="sans-stroke-13">175 <object name="gamesBox" style="ModernList" sprite_asc="ModernArrowDown" default_column="name" sprite_desc="ModernArrowUp" sprite_not_sorted="ModernNotSorted" 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> -
source/gui/COList.cpp
19 19 #include "i18n/L10n.h" 20 20 21 21 #include "ps/CLogger.h" 22 #include "soundmanager/ISoundManager.h" 22 23 23 COList::COList() : CList(),m_HeadingHeight(30.f) 24 COList::COList() : CList(),m_HeadingHeight(30.f),m_SelectedDef(-1),m_SelectedColumnOrder(1) 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_column_order"); 30 AddSetting(GUIST_CStr, "default_column"); 31 AddSetting(GUIST_int, "selected_def"); 32 AddSetting(GUIST_CGUISpriteInstance, "sprite_asc"); // Show the order of sorting 33 AddSetting(GUIST_CGUISpriteInstance, "sprite_desc"); 34 AddSetting(GUIST_CGUISpriteInstance, "sprite_not_sorted"); 35 36 // Nothing is selected by default. 37 GUI<CStr>::SetSetting(this, "selected_column", ""); 38 GUI<int>::SetSetting(this, "selected_column_order", 1); 39 GUI<int>::SetSetting(this, "selected_def", -1); 26 40 } 27 41 28 42 void COList::SetupText() … … 66 80 float buffer_zone=0.f; 67 81 GUI<float>::GetSetting(this, "buffer_zone", buffer_zone); 68 82 83 CStr defaultColumn; 84 GUI<CStr>::GetSetting(this, "default_column", defaultColumn); 85 defaultColumn = "list_" + defaultColumn; 69 86 70 87 for (unsigned int c=0; c<m_ObjectsDefs.size(); ++c) 71 88 { … … 74 91 gui_string.SetValue(m_ObjectsDefs[c].m_Heading); 75 92 *text = GetGUI()->GenerateText(gui_string, font, width, buffer_zone, this); 76 93 AddText(text); 94 95 if (m_SelectedDef == -1 && defaultColumn == m_ObjectsDefs[c].m_Id) 96 m_SelectedDef = c; 77 97 } 78 98 79 99 … … 119 139 void COList::HandleMessage(SGUIMessage &Message) 120 140 { 121 141 CList::HandleMessage(Message); 142 143 switch (Message.type) 144 { 145 // If somebody clicks on the column heading 146 case GUIM_MOUSE_PRESS_LEFT: 147 { 148 bool sortable; 149 GUI<bool>::GetSetting(this, "sortable", sortable); 150 if (!sortable) 151 return; 152 153 CPos mouse = GetMousePos(); 154 if (!m_CachedActualSize.PointInside(mouse)) 155 return; 156 157 float xpos = 0; 158 for (unsigned int def = 0; def < m_ObjectsDefs.size(); ++def) 159 { 160 float width = m_ObjectsDefs[def].m_Width; 161 // Check if it's a decimal value, and if so, assume relative positioning. 162 if (m_ObjectsDefs[def].m_Width < 1 && m_ObjectsDefs[def].m_Width > 0) 163 width *= m_TotalAvalibleColumnWidth; 164 CPos leftTopCorner = m_CachedActualSize.TopLeft() + CPos(xpos, 4); 165 if (mouse.x >= leftTopCorner.x && 166 mouse.x < leftTopCorner.x + width && 167 mouse.y < leftTopCorner.y + m_HeadingHeight) 168 { 169 if (static_cast<int> (def) != m_SelectedDef) 170 { 171 m_SelectedColumnOrder = 1; 172 m_SelectedDef = def; 173 } 174 else 175 m_SelectedColumnOrder = -m_SelectedColumnOrder; 176 GUI<CStr>::SetSetting(this, "selected_column", m_ObjectsDefs[def].m_Id.substr(5)); 177 GUI<int>::SetSetting(this, "selected_column_order", m_SelectedColumnOrder); 178 GUI<int>::SetSetting(this, "selected_def", def); 179 ScriptEvent("selectioncolumnchange"); 180 181 CStrW soundPath; 182 if (g_SoundManager && GUI<CStrW>::GetSetting(this, "sound_selected", soundPath) == PSRETURN_OK && !soundPath.empty()) 183 g_SoundManager->PlayAsUI(soundPath.c_str(), false); 184 185 return; 186 } 187 xpos += width; 188 } 189 return; 190 } 191 default: 192 return; 193 } 122 194 } 123 195 124 196 bool COList::HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile) … … 307 379 CRect rect_head(m_CachedActualSize.left, m_CachedActualSize.top, m_CachedActualSize.right, 308 380 m_CachedActualSize.top + m_HeadingHeight); 309 381 GetGUI()->DrawSprite(*sprite_heading, cell_id, bz, rect_head); 382 383 CGUISpriteInstance *sprite_order, *sprite_not_sorted; 384 if (m_SelectedColumnOrder != -1) 385 GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite_asc", sprite_order); 386 else 387 GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite_desc", sprite_order); 388 GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite_not_sorted", sprite_not_sorted); 310 389 311 390 float xpos = 0; 312 391 for (unsigned int def=0; def< m_ObjectsDefs.size(); ++def) 313 392 { 314 DrawText(def, color, m_CachedActualSize.TopLeft() + CPos(xpos, 4), bz+0.1f, rect_head);315 393 // Check if it's a decimal value, and if so, assume relative positioning. 394 float width = m_ObjectsDefs[def].m_Width; 316 395 if (m_ObjectsDefs[def].m_Width < 1 && m_ObjectsDefs[def].m_Width > 0) 317 xpos += m_ObjectsDefs[def].m_Width * m_TotalAvalibleColumnWidth; 396 width *= m_TotalAvalibleColumnWidth; 397 398 CPos leftTopCorner = m_CachedActualSize.TopLeft() + CPos(xpos, 0); 399 CGUISpriteInstance *sprite; 400 // If the list sorted by current column 401 if (m_SelectedDef == static_cast<int> (def)) 402 sprite = sprite_order; 318 403 else 319 xpos += m_ObjectsDefs[def].m_Width; 404 sprite = sprite_not_sorted; 405 GetGUI()->DrawSprite(*sprite, cell_id, bz + 0.1f, CRect(leftTopCorner + CPos(width - 16, 0), leftTopCorner + CPos(width, 16))); 406 407 DrawText(def, color, leftTopCorner + CPos(0, 4), bz + 0.1f, rect_head); 408 xpos += width; 320 409 } 321 410 322 411 for (int i=0; i<(int)pList->m_Items.size(); ++i) -
source/gui/COList.h
1 /* Copyright (C) 201 4Wildfire Games.1 /* Copyright (C) 2015 Wildfire Games. 2 2 * This file is part of 0 A.D. 3 3 * 4 4 * 0 A.D. is free software: you can redistribute it and/or modify … … 70 70 virtual CRect GetListRect() const; 71 71 72 72 std::vector<ObjectDef> m_ObjectsDefs; 73 int m_SelectedDef; 74 int m_SelectedColumnOrder; 73 75 74 76 private: 75 77 float m_HeadingHeight;