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