]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - data/qcsrc/menu/voret/serverlist.c
Optimize menu code for my last change
[voretournament/voretournament.git] / data / qcsrc / menu / voret / serverlist.c
1 #ifdef INTERFACE\r
2 CLASS(VoretServerList) EXTENDS(VoretListBox)\r
3         METHOD(VoretServerList, configureVoretServerList, void(entity))\r
4         ATTRIB(VoretServerList, rowsPerItem, float, 1)\r
5         METHOD(VoretServerList, draw, void(entity))\r
6         METHOD(VoretServerList, drawListBoxItem, void(entity, float, vector, float))\r
7         METHOD(VoretServerList, clickListBoxItem, void(entity, float, vector))\r
8         METHOD(VoretServerList, resizeNotify, void(entity, vector, vector, vector, vector))\r
9         METHOD(VoretServerList, keyDown, float(entity, float, float, float))\r
10 \r
11         ATTRIB(VoretServerList, realFontSize, vector, '0 0 0')\r
12         ATTRIB(VoretServerList, realUpperMargin, float, 0)\r
13         ATTRIB(VoretServerList, columnPingOrigin, float, 0)\r
14         ATTRIB(VoretServerList, columnPingSize, float, 0)\r
15         ATTRIB(VoretServerList, columnNameOrigin, float, 0)\r
16         ATTRIB(VoretServerList, columnNameSize, float, 0)\r
17         ATTRIB(VoretServerList, columnMapOrigin, float, 0)\r
18         ATTRIB(VoretServerList, columnMapSize, float, 0)\r
19         ATTRIB(VoretServerList, columnTypeOrigin, float, 0)\r
20         ATTRIB(VoretServerList, columnTypeSize, float, 0)\r
21         ATTRIB(VoretServerList, columnPlayersOrigin, float, 0)\r
22         ATTRIB(VoretServerList, columnPlayersSize, float, 0)\r
23 \r
24         ATTRIB(VoretServerList, selectedServer, string, string_null) // to restore selected server when needed\r
25         METHOD(VoretServerList, setSelected, void(entity, float))\r
26         METHOD(VoretServerList, setSortOrder, void(entity, float, float))\r
27         ATTRIB(VoretServerList, filterShowEmpty, float, 1)\r
28         ATTRIB(VoretServerList, filterShowFull, float, 1)\r
29         ATTRIB(VoretServerList, filterString, string, string_null)\r
30         ATTRIB(VoretServerList, controlledTextbox, entity, NULL)\r
31         ATTRIB(VoretServerList, ipAddressBox, entity, NULL)\r
32         ATTRIB(VoretServerList, favoriteButton, entity, NULL)\r
33         ATTRIB(VoretServerList, nextRefreshTime, float, 0)\r
34         METHOD(VoretServerList, refreshServerList, void(entity, float)) // refresh mode: 0 = just reparametrize, 1 = send new requests, 2 = clear\r
35         ATTRIB(VoretServerList, needsRefresh, float, 1)\r
36         METHOD(VoretServerList, focusEnter, void(entity))\r
37         METHOD(VoretServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)))\r
38         ATTRIB(VoretServerList, sortButton1, entity, NULL)\r
39         ATTRIB(VoretServerList, sortButton2, entity, NULL)\r
40         ATTRIB(VoretServerList, sortButton3, entity, NULL)\r
41         ATTRIB(VoretServerList, sortButton4, entity, NULL)\r
42         ATTRIB(VoretServerList, sortButton5, entity, NULL)\r
43         ATTRIB(VoretServerList, connectButton, entity, NULL)\r
44         ATTRIB(VoretServerList, infoButton, entity, NULL)\r
45         ATTRIB(VoretServerList, currentSortOrder, float, 0)\r
46         ATTRIB(VoretServerList, currentSortField, float, -1)\r
47         ATTRIB(VoretServerList, lastClickedServer, float, -1)\r
48         ATTRIB(VoretServerList, lastClickedTime, float, 0)\r
49 \r
50         ATTRIB(VoretServerList, ipAddressBoxFocused, float, -1)\r
51 ENDCLASS(VoretServerList)\r
52 entity makeVoretServerList();\r
53 void ServerList_Connect_Click(entity btn, entity me);\r
54 void ServerList_ShowEmpty_Click(entity box, entity me);\r
55 void ServerList_ShowFull_Click(entity box, entity me);\r
56 void ServerList_Filter_Change(entity box, entity me);\r
57 void ServerList_Favorite_Click(entity btn, entity me);\r
58 void ServerList_Info_Click(entity btn, entity me);\r
59 #endif\r
60 \r
61 #ifdef IMPLEMENTATION\r
62 float SLIST_FIELD_CNAME;\r
63 float SLIST_FIELD_PING;\r
64 float SLIST_FIELD_GAME;\r
65 float SLIST_FIELD_MOD;\r
66 float SLIST_FIELD_MAP;\r
67 float SLIST_FIELD_NAME;\r
68 float SLIST_FIELD_MAXPLAYERS;\r
69 float SLIST_FIELD_NUMPLAYERS;\r
70 float SLIST_FIELD_NUMHUMANS;\r
71 float SLIST_FIELD_NUMBOTS;\r
72 float SLIST_FIELD_PROTOCOL;\r
73 float SLIST_FIELD_FREESLOTS;\r
74 float SLIST_FIELD_PLAYERS;\r
75 float SLIST_FIELD_QCSTATUS;\r
76 float SLIST_FIELD_ISFAVORITE;\r
77 void ServerList_UpdateFieldIDs()\r
78 {\r
79         SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );\r
80         SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );\r
81         SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );\r
82         SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );\r
83         SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );\r
84         SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );\r
85         SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );\r
86         SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );\r
87         SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );\r
88         SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );\r
89         SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );\r
90         SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );\r
91         SLIST_FIELD_PLAYERS = gethostcacheindexforkey( "players" );\r
92         SLIST_FIELD_QCSTATUS = gethostcacheindexforkey( "qcstatus" );\r
93         SLIST_FIELD_ISFAVORITE = gethostcacheindexforkey( "isfavorite" );\r
94 }\r
95 \r
96 float IsFavorite(string srv)\r
97 {\r
98         float i, n;\r
99         srv = netaddress_resolve(srv, 26000);\r
100         n = tokenize_console(cvar_string("net_slist_favorites"));\r
101         for(i = 0; i < n; ++i)\r
102                 if(srv == netaddress_resolve(argv(i), 26000))\r
103                         return TRUE;\r
104         return FALSE;\r
105 }\r
106 \r
107 void ToggleFavorite(string srv)\r
108 {\r
109         string s, s0, s1, s2, srv_resolved;\r
110         float i, n;\r
111         srv_resolved = netaddress_resolve(srv, 26000);\r
112         s = cvar_string("net_slist_favorites");\r
113         n = tokenize_console(s);\r
114         for(i = 0; i < n; ++i)\r
115                 if(srv_resolved == netaddress_resolve(argv(i), 26000))\r
116                 {\r
117                         s0 = s1 = s2 = "";\r
118                         if(i > 0)\r
119                                 s0 = substring(s, 0, argv_end_index(i - 1));\r
120                         if(i < n-1)\r
121                                 s2 = substring(s, argv_start_index(i + 1), -1);\r
122                         if(s0 != "" && s2 != "")\r
123                                 s1 = " ";\r
124                         print("s0 = >>", s0, "<<\ns1 = >>", s1, "<<\ns2 = >>", s2, "<<\n");\r
125                         cvar_set("net_slist_favorites", strcat(s0, s1, s2));\r
126                         return;\r
127                 }\r
128         \r
129         s1 = "";\r
130         if(s != "")\r
131                 s1 = " ";\r
132         cvar_set("net_slist_favorites", strcat(s, " ", srv));\r
133 \r
134         resorthostcache();\r
135 }\r
136 \r
137 entity makeVoretServerList()\r
138 {\r
139         entity me;\r
140         me = spawnVoretServerList();\r
141         me.configureVoretServerList(me);\r
142         return me;\r
143 }\r
144 void configureVoretServerListVoretServerList(entity me)\r
145 {\r
146         me.configureVoretListBox(me);\r
147 \r
148         ServerList_UpdateFieldIDs();\r
149 \r
150         me.nItems = 0;\r
151 }\r
152 void setSelectedVoretServerList(entity me, float i)\r
153 {\r
154         float save;\r
155         save = me.selectedItem;\r
156         setSelectedListBox(me, i);\r
157         /*\r
158         if(me.selectedItem == save)\r
159                 return;\r
160         */\r
161         if(me.nItems == 0)\r
162                 return;\r
163         if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)\r
164                 return; // sorry, it would be wrong\r
165 \r
166         if(me.selectedServer)\r
167                 strunzone(me.selectedServer);\r
168         me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));\r
169 \r
170         me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);\r
171         me.ipAddressBox.cursorPos = strlen(me.selectedServer);\r
172         me.ipAddressBoxFocused = -1;\r
173 }\r
174 void refreshServerListVoretServerList(entity me, float mode)\r
175 {\r
176         // 0: just reparametrize\r
177         // 1: also ask for new servers\r
178         // 2: clear\r
179         //print("refresh of type ", ftos(mode), "\n");\r
180         /* if(mode == 2) // borken\r
181         {\r
182                 // clear list\r
183                 localcmd("net_slist\n");\r
184                 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later\r
185         }\r
186         else */\r
187         {\r
188                 float m, o;\r
189                 string s, typestr, modstr;\r
190                 s = me.filterString;\r
191 \r
192                 m = strstrofs(s, ":", 0);\r
193                 if(m >= 0)\r
194                 {\r
195                         typestr = substring(s, 0, m);\r
196                         s = substring(s, m + 1, strlen(s) - m - 1);\r
197                         while(substring(s, 0, 1) == " ")\r
198                                 s = substring(s, 1, strlen(s) - 1);\r
199                 }\r
200                 else\r
201                         typestr = "";\r
202 \r
203                 modstr = cvar_string("menu_slist_modfilter");\r
204 \r
205                 m = SLIST_MASK_AND - 1;\r
206                 resethostcachemasks();\r
207                 if(!me.filterShowFull)\r
208                         sethostcachemasknumber(++m, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL);\r
209                 if(!me.filterShowEmpty)\r
210                         sethostcachemasknumber(++m, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);\r
211                 if(typestr != "")\r
212                         sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(typestr, ":"), SLIST_TEST_STARTSWITH);\r
213                 if(modstr != "")\r
214                 {\r
215                         if(substring(modstr, 0, 1) == "!")\r
216                                 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(substring(modstr, 1, strlen(modstr) - 1)), SLIST_TEST_NOTEQUAL);\r
217                         else\r
218                                 sethostcachemaskstring(++m, SLIST_FIELD_MOD, resolvemod(modstr), SLIST_TEST_EQUAL);\r
219                 }\r
220                 m = SLIST_MASK_OR - 1;\r
221                 if(s != "")\r
222                 {\r
223                         sethostcachemaskstring(++m, SLIST_FIELD_NAME, s, SLIST_TEST_CONTAINS);\r
224                         sethostcachemaskstring(++m, SLIST_FIELD_MAP, s, SLIST_TEST_CONTAINS);\r
225                         sethostcachemaskstring(++m, SLIST_FIELD_PLAYERS, s, SLIST_TEST_CONTAINS);\r
226                         sethostcachemaskstring(++m, SLIST_FIELD_QCSTATUS, strcat(s, ":"), SLIST_TEST_STARTSWITH);\r
227                 }\r
228                 o = 2; // favorites first\r
229                 if(me.currentSortOrder < 0)\r
230                         o |= 1; // descending\r
231                 sethostcachesort(me.currentSortField, o);\r
232                 resorthostcache();\r
233                 if(mode >= 1)\r
234                         refreshhostcache();\r
235         }\r
236 }\r
237 void focusEnterVoretServerList(entity me)\r
238 {\r
239         if(time < me.nextRefreshTime)\r
240         {\r
241                 //print("sorry, no refresh yet\n");\r
242                 return;\r
243         }\r
244         me.nextRefreshTime = time + 10;\r
245         me.refreshServerList(me, 1);\r
246 }\r
247 void drawVoretServerList(entity me)\r
248 {\r
249         float i, found, owned;\r
250 \r
251         if(me.currentSortField == -1)\r
252         {\r
253                 me.setSortOrder(me, SLIST_FIELD_PING, +1);\r
254                 me.refreshServerList(me, 2);\r
255         }\r
256         else if(me.needsRefresh == 1)\r
257         {\r
258                 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed\r
259         }\r
260         else if(me.needsRefresh == 2)\r
261         {\r
262                 me.needsRefresh = 0;\r
263                 me.refreshServerList(me, 0);\r
264         }\r
265 \r
266         owned = ((me.selectedServer == me.ipAddressBox.text) && (me.ipAddressBox.text != ""));\r
267 \r
268         me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);\r
269 \r
270         me.connectButton.disabled = ((me.nItems == 0) && (me.ipAddressBox.text == ""));\r
271         me.infoButton.disabled = ((me.nItems == 0) || !owned);\r
272 \r
273         found = 0;\r
274         if(me.selectedServer)\r
275         {\r
276                 for(i = 0; i < me.nItems; ++i)\r
277                         if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)\r
278                         {\r
279                                 if(i != me.selectedItem)\r
280                                 {\r
281                                         me.lastClickedServer = -1;\r
282                                         me.selectedItem = i;\r
283                                 }\r
284                                 found = 1;\r
285                                 break;\r
286                         }\r
287         }\r
288         if(!found)\r
289                 if(me.nItems > 0)\r
290                 {\r
291                         if(me.selectedItem >= me.nItems)\r
292                                 me.selectedItem = me.nItems - 1;\r
293                         if(me.selectedServer)\r
294                                 strunzone(me.selectedServer);\r
295                         me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));\r
296                 }\r
297 \r
298         if(owned)\r
299         {\r
300                 if(me.selectedServer != me.ipAddressBox.text)\r
301                 {\r
302                         me.ipAddressBox.setText(me.ipAddressBox, me.selectedServer);\r
303                         me.ipAddressBox.cursorPos = strlen(me.selectedServer);\r
304                         me.ipAddressBoxFocused = -1;\r
305                 }\r
306         }\r
307 \r
308         if(me.ipAddressBoxFocused != me.ipAddressBox.focused)\r
309         {\r
310                 if(me.ipAddressBox.focused || me.ipAddressBoxFocused < 0)\r
311                 {\r
312                         if(IsFavorite(me.ipAddressBox.text))\r
313                                 me.favoriteButton.setText(me.favoriteButton, "Remove");\r
314                         else\r
315                                 me.favoriteButton.setText(me.favoriteButton, "Bookmark");\r
316                 }\r
317                 me.ipAddressBoxFocused = me.ipAddressBox.focused;\r
318         }\r
319 \r
320         drawListBox(me);\r
321 }\r
322 void ServerList_PingSort_Click(entity btn, entity me)\r
323 {\r
324         me.setSortOrder(me, SLIST_FIELD_PING, +1);\r
325 }\r
326 void ServerList_NameSort_Click(entity btn, entity me)\r
327 {\r
328         me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?\r
329 }\r
330 void ServerList_MapSort_Click(entity btn, entity me)\r
331 {\r
332         me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?\r
333 }\r
334 void ServerList_PlayerSort_Click(entity btn, entity me)\r
335 {\r
336         me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);\r
337 }\r
338 void ServerList_TypeSort_Click(entity btn, entity me)\r
339 {\r
340         string s, t;\r
341         float i, m;\r
342         s = me.filterString;\r
343         m = strstrofs(s, ":", 0);\r
344         if(m >= 0)\r
345         {\r
346                 s = substring(s, 0, m);\r
347                 while(substring(s, m+1, 1) == " ") // skip spaces\r
348                         ++m;\r
349         }\r
350         else\r
351                 s = "";\r
352 \r
353         for(i = 1; ; ++i) // 20 modes ought to be enough for anyone\r
354         {\r
355                 t = GametypeNameFromType(i);\r
356                 if(i > 1)\r
357                         if(t == GametypeNameFromType(0)) // it repeats (default case)\r
358                         {\r
359                                 // no type was found\r
360                                 // choose the first one\r
361                                 s = t;\r
362                                 break;\r
363                         }\r
364                 if(s == GametypeNameFromType(i))\r
365                 {\r
366                         // the type was found\r
367                         // choose the next one\r
368                         s = GametypeNameFromType(i + 1);\r
369                         if(s == GametypeNameFromType(0))\r
370                                 s = "";\r
371                         break;\r
372                 }\r
373         }\r
374 \r
375         if(s != "")\r
376                 s = strcat(s, ":");\r
377         s = strcat(s, substring(me.filterString, m+1, strlen(me.filterString) - m - 1));\r
378 \r
379         me.controlledTextbox.setText(me.controlledTextbox, s);\r
380         me.controlledTextbox.keyDown(me.controlledTextbox, K_END, 0, 0);\r
381         me.controlledTextbox.keyUp(me.controlledTextbox, K_END, 0, 0);\r
382         //ServerList_Filter_Change(me.controlledTextbox, me);\r
383 }\r
384 void ServerList_Filter_Change(entity box, entity me)\r
385 {\r
386         if(me.filterString)\r
387                 strunzone(me.filterString);\r
388         if(box.text != "")\r
389                 me.filterString = strzone(box.text);\r
390         else\r
391                 me.filterString = string_null;\r
392         me.refreshServerList(me, 0);\r
393 \r
394         me.ipAddressBox.setText(me.ipAddressBox, "");\r
395         me.ipAddressBox.cursorPos = 0;\r
396         me.ipAddressBoxFocused = -1;\r
397 }\r
398 void ServerList_ShowEmpty_Click(entity box, entity me)\r
399 {\r
400         box.setChecked(box, me.filterShowEmpty = !me.filterShowEmpty);\r
401         me.refreshServerList(me, 0);\r
402 \r
403         me.ipAddressBox.setText(me.ipAddressBox, "");\r
404         me.ipAddressBox.cursorPos = 0;\r
405         me.ipAddressBoxFocused = -1;\r
406 }\r
407 void ServerList_ShowFull_Click(entity box, entity me)\r
408 {\r
409         box.setChecked(box, me.filterShowFull = !me.filterShowFull);\r
410         me.refreshServerList(me, 0);\r
411 \r
412         me.ipAddressBox.setText(me.ipAddressBox, "");\r
413         me.ipAddressBox.cursorPos = 0;\r
414         me.ipAddressBoxFocused = -1;\r
415 }\r
416 void setSortOrderVoretServerList(entity me, float field, float direction)\r
417 {\r
418         if(me.currentSortField == field)\r
419                 direction = -me.currentSortOrder;\r
420         me.currentSortOrder = direction;\r
421         me.currentSortField = field;\r
422         me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);\r
423         me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);\r
424         me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);\r
425         me.sortButton4.forcePressed = 0;\r
426         me.sortButton5.forcePressed = (field == SLIST_FIELD_NUMHUMANS);\r
427         me.selectedItem = 0;\r
428         if(me.selectedServer)\r
429                 strunzone(me.selectedServer);\r
430         me.selectedServer = string_null;\r
431         me.refreshServerList(me, 0);\r
432 }\r
433 void positionSortButtonVoretServerList(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)\r
434 {\r
435         vector originInLBSpace, sizeInLBSpace;\r
436         originInLBSpace = eY * (-me.itemHeight);\r
437         sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);\r
438 \r
439         vector originInDialogSpace, sizeInDialogSpace;\r
440         originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);\r
441         sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);\r
442 \r
443         btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;\r
444         btn.Container_size_x   =                         sizeInDialogSpace_x * theSize;\r
445         btn.setText(btn, theTitle);\r
446         btn.onClick = theFunc;\r
447         btn.onClickEntity = me;\r
448         btn.resized = 1;\r
449 }\r
450 void resizeNotifyVoretServerList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)\r
451 {\r
452         resizeNotifyVoretListBox(me, relOrigin, relSize, absOrigin, absSize);\r
453 \r
454         me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);\r
455         me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));\r
456         me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);\r
457 \r
458         me.columnPingOrigin = 0;\r
459         me.columnPingSize = me.realFontSize_x * 4;\r
460         me.columnMapSize = me.realFontSize_x * 12;\r
461         me.columnTypeSize = me.realFontSize_x * 4;\r
462         me.columnPlayersSize = me.realFontSize_x * 6;\r
463         me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - me.columnTypeSize - 4 * me.realFontSize_x;\r
464         me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;\r
465         me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;\r
466         me.columnTypeOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;\r
467         me.columnPlayersOrigin = me.columnTypeOrigin + me.columnTypeSize + me.realFontSize_x;\r
468 \r
469         me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, "Ping", ServerList_PingSort_Click);\r
470         me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, "Host name", ServerList_NameSort_Click);\r
471         me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, "Map", ServerList_MapSort_Click);\r
472         me.positionSortButton(me, me.sortButton4, me.columnTypeOrigin, me.columnTypeSize, "Type", ServerList_TypeSort_Click);\r
473         me.positionSortButton(me, me.sortButton5, me.columnPlayersOrigin, me.columnPlayersSize, "Players", ServerList_PlayerSort_Click);\r
474 \r
475         float f;\r
476         f = me.currentSortField;\r
477         if(f >= 0)\r
478         {\r
479                 me.currentSortField = -1;\r
480                 me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order\r
481         }\r
482 }\r
483 void ServerList_Connect_Click(entity btn, entity me)\r
484 {\r
485         if(me.ipAddressBox.text == "")\r
486                 localcmd("connect ", me.selectedServer, "\n");\r
487         else\r
488                 localcmd("connect ", me.ipAddressBox.text, "\n");\r
489 }\r
490 void ServerList_Favorite_Click(entity btn, entity me)\r
491 {\r
492         string ipstr;\r
493         ipstr = netaddress_resolve(me.ipAddressBox.text, 26000);\r
494         if(ipstr != "")\r
495         {\r
496                 ToggleFavorite(me.ipAddressBox.text);\r
497                 me.ipAddressBoxFocused = -1;\r
498         }\r
499 }\r
500 void ServerList_Info_Click(entity btn, entity me)\r
501 {\r
502         main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);\r
503         DialogOpenButton_Click(me, main.serverInfoDialog);\r
504 }\r
505 void clickListBoxItemVoretServerList(entity me, float i, vector where)\r
506 {\r
507         if(i == me.lastClickedServer)\r
508                 if(time < me.lastClickedTime + 0.3)\r
509                 {\r
510                         // DOUBLE CLICK!\r
511                         ServerList_Connect_Click(NULL, me);\r
512                 }\r
513         me.lastClickedServer = i;\r
514         me.lastClickedTime = time;\r
515 }\r
516 void drawListBoxItemVoretServerList(entity me, float i, vector absSize, float isSelected)\r
517 {\r
518         // layout: Ping, Server name, Map name, NP, TP, MP\r
519         string s;\r
520         float p;\r
521         vector theColor;\r
522         float theAlpha;\r
523 \r
524         if(isSelected)\r
525                 draw_Fill('0 0 0', '1 1 0', SKINCOLOR_LISTBOX_SELECTED, SKINALPHA_LISTBOX_SELECTED);\r
526 \r
527         if(gethostcachenumber(SLIST_FIELD_NUMPLAYERS, i) >= gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))\r
528                 theAlpha = SKINALPHA_SERVERLIST_FULL;\r
529         else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))\r
530                 theAlpha = SKINALPHA_SERVERLIST_EMPTY;\r
531         else\r
532                 theAlpha = 1;\r
533 \r
534         p = gethostcachenumber(SLIST_FIELD_PING, i);\r
535 #define PING_LOW 75\r
536 #define PING_MED 200\r
537 #define PING_HIGH 500\r
538         if(p < PING_LOW)\r
539                 theColor = SKINCOLOR_SERVERLIST_LOWPING + (SKINCOLOR_SERVERLIST_MEDPING - SKINCOLOR_SERVERLIST_LOWPING) * (p / PING_LOW);\r
540         else if(p < PING_MED)\r
541                 theColor = SKINCOLOR_SERVERLIST_MEDPING + (SKINCOLOR_SERVERLIST_HIGHPING - SKINCOLOR_SERVERLIST_MEDPING) * ((p - PING_LOW) / (PING_MED - PING_LOW));\r
542         else if(p < PING_HIGH)\r
543         {\r
544                 theColor = SKINCOLOR_SERVERLIST_HIGHPING;\r
545                 theAlpha *= 1 + (SKINALPHA_SERVERLIST_HIGHPING - 1) * ((p - PING_MED) / (PING_HIGH - PING_MED));\r
546         }\r
547         else\r
548         {\r
549                 theColor = eX;\r
550                 theAlpha *= SKINALPHA_SERVERLIST_HIGHPING;\r
551         }\r
552 \r
553         if(gethostcachenumber(SLIST_FIELD_ISFAVORITE, i))\r
554         {\r
555                 theColor = theColor * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINCOLOR_SERVERLIST_FAVORITE * SKINALPHA_SERVERLIST_FAVORITE;\r
556                 theAlpha = theAlpha * (1 - SKINALPHA_SERVERLIST_FAVORITE) + SKINALPHA_SERVERLIST_FAVORITE;\r
557         }\r
558 \r
559         s = ftos(p);\r
560         draw_Text(me.realUpperMargin * eY + (me.columnPingSize - draw_TextWidth(s, 0, me.realFontSize)) * eX, s, me.realFontSize, theColor, theAlpha, 0);\r
561         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize, 0, me.realFontSize);\r
562         draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);\r
563         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize, 0, me.realFontSize);\r
564         draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);\r
565         s = gethostcachestring(SLIST_FIELD_QCSTATUS, i);\r
566         p = strstrofs(s, ":", 0);\r
567         if(p >= 0)\r
568                 s = substring(s, 0, p);\r
569         else\r
570                 s = "";\r
571         s = draw_TextShortenToWidth(s, me.columnMapSize, 0, me.realFontSize);\r
572         draw_Text(me.realUpperMargin * eY + (me.columnTypeOrigin + (me.columnTypeSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);\r
573         s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));\r
574         draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s, 0, me.realFontSize)) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha, 0);\r
575 }\r
576 \r
577 float keyDownVoretServerList(entity me, float scan, float ascii, float shift)\r
578 {\r
579         float i;\r
580         vector org, sz;\r
581 \r
582         org = boxToGlobal(eY * (me.selectedItem * me.itemHeight - me.scrollPos), me.origin, me.size);\r
583         sz = boxToGlobalSize(eY * me.itemHeight + eX * (1 - me.controlWidth), me.size);\r
584 \r
585         if(scan == K_ENTER)\r
586         {\r
587                 ServerList_Connect_Click(NULL, me);\r
588                 return 1;\r
589         }\r
590         else if(scan == K_MOUSE2 || scan == K_SPACE)\r
591         {\r
592                 main.serverInfoDialog.loadServerInfo(main.serverInfoDialog, me.selectedItem);\r
593                 DialogOpenButton_Click_withCoords(me, main.serverInfoDialog, org, sz);\r
594         }\r
595         else if(scan == K_INS || scan == K_MOUSE3)\r
596         {\r
597                 i = me.selectedItem;\r
598                 if(i < me.nItems)\r
599                 {\r
600                         ToggleFavorite(me.selectedServer);\r
601                         me.ipAddressBoxFocused = -1;\r
602                 }\r
603         }\r
604         else if(keyDownListBox(me, scan, ascii, shift))\r
605                 return 1;\r
606         else if(!me.controlledTextbox)\r
607                 return 0;\r
608         else\r
609                 return me.controlledTextbox.keyDown(me.controlledTextbox, scan, ascii, shift);\r
610 }\r
611 #endif\r