]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/menu-div0test/nexuiz/serverlist.c
inputboxing!
[divverent/nexuiz.git] / data / qcsrc / menu-div0test / 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
10         ATTRIB(NexuizServerList, realFontSize, vector, '0 0 0')
11         ATTRIB(NexuizServerList, realUpperMargin, float, 0)
12         ATTRIB(NexuizServerList, columnPingOrigin, float, 0)
13         ATTRIB(NexuizServerList, columnPingSize, float, 0)
14         ATTRIB(NexuizServerList, columnNameOrigin, float, 0)
15         ATTRIB(NexuizServerList, columnNameSize, float, 0)
16         ATTRIB(NexuizServerList, columnMapOrigin, float, 0)
17         ATTRIB(NexuizServerList, columnMapSize, float, 0)
18         ATTRIB(NexuizServerList, columnPlayersOrigin, float, 0)
19         ATTRIB(NexuizServerList, columnPlayersSize, float, 0)
20
21         ATTRIB(NexuizServerList, selectedServer, string, string_null) // to restore selected server when needed
22         METHOD(NexuizServerList, setSelected, void(entity, float))
23         METHOD(NexuizServerList, setSortOrder, void(entity, float, float))
24         ATTRIB(NexuizServerList, filterShowEmpty, float, 1)
25         ATTRIB(NexuizServerList, filterShowFull, float, 1)
26         ATTRIB(NexuizServerList, nextRefreshTime, float, 0)
27         METHOD(NexuizServerList, refreshServerList, void(entity, float)) // refresh mode: 0 = just reparametrize, 1 = send new requests, 2 = clear
28         ATTRIB(NexuizServerList, needsRefresh, float, 1)
29         METHOD(NexuizServerList, focusEnter, void(entity))
30         METHOD(NexuizServerList, positionSortButton, void(entity, entity, float, float, string, void(entity, entity)))
31         ATTRIB(NexuizServerList, sortButton1, entity, NULL)
32         ATTRIB(NexuizServerList, sortButton2, entity, NULL)
33         ATTRIB(NexuizServerList, sortButton3, entity, NULL)
34         ATTRIB(NexuizServerList, sortButton4, entity, NULL)
35         ATTRIB(NexuizServerList, connectButton, entity, NULL)
36         ATTRIB(NexuizServerList, currentSortOrder, float, 0)
37         ATTRIB(NexuizServerList, currentSortField, float, -1)
38         ATTRIB(NexuizServerList, lastClickedServer, float, -1)
39         ATTRIB(NexuizServerList, lastClickedTime, float, 0)
40 ENDCLASS(NexuizServerList)
41 entity makeNexuizServerList();
42 void ServerList_Connect_Click(entity btn, entity me);
43 void ServerList_ShowEmpty_Click(entity box, entity me);
44 void ServerList_ShowFull_Click(entity box, entity me);
45 #endif
46
47 #ifdef IMPLEMENTATION
48 float SLIST_FIELD_CNAME;
49 float SLIST_FIELD_PING;
50 float SLIST_FIELD_GAME;
51 float SLIST_FIELD_MOD;
52 float SLIST_FIELD_MAP;
53 float SLIST_FIELD_NAME;
54 float SLIST_FIELD_MAXPLAYERS;
55 float SLIST_FIELD_NUMPLAYERS;
56 float SLIST_FIELD_NUMHUMANS;
57 float SLIST_FIELD_NUMBOTS;
58 float SLIST_FIELD_PROTOCOL;
59 float SLIST_FIELD_FREESLOTS;
60 void ServerList_UpdateFieldIDs()
61 {
62         SLIST_FIELD_CNAME = gethostcacheindexforkey( "cname" );
63         SLIST_FIELD_PING = gethostcacheindexforkey( "ping" );
64         SLIST_FIELD_GAME = gethostcacheindexforkey( "game" );
65         SLIST_FIELD_MOD = gethostcacheindexforkey( "mod" );
66         SLIST_FIELD_MAP = gethostcacheindexforkey( "map" );
67         SLIST_FIELD_NAME = gethostcacheindexforkey( "name" );
68         SLIST_FIELD_MAXPLAYERS = gethostcacheindexforkey( "maxplayers" );
69         SLIST_FIELD_NUMPLAYERS = gethostcacheindexforkey( "numplayers" );
70         SLIST_FIELD_NUMHUMANS = gethostcacheindexforkey( "numhumans" );
71         SLIST_FIELD_NUMBOTS = gethostcacheindexforkey( "numbots" );
72         SLIST_FIELD_PROTOCOL = gethostcacheindexforkey( "protocol" );
73         SLIST_FIELD_FREESLOTS = gethostcacheindexforkey( "freeslots" );
74 }
75
76 entity makeNexuizServerList()
77 {
78         entity me;
79         me = spawnNexuizServerList();
80         me.configureNexuizServerList(me);
81         return me;
82 }
83 void configureNexuizServerListNexuizServerList(entity me)
84 {
85         me.configureNexuizListBox(me);
86
87         ServerList_UpdateFieldIDs();
88
89         me.nItems = 0;
90 }
91 void setSelectedNexuizServerList(entity me, float i)
92 {
93         float save;
94         save = me.selectedItem;
95         setSelectedListBox(me, i);
96         /*
97         if(me.selectedItem == save)
98                 return;
99         */
100         if(me.nItems == 0)
101                 return;
102         if(gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT) != me.nItems)
103                 return; // sorry, it would be wrong
104         if(me.selectedServer)
105                 strunzone(me.selectedServer);
106         me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
107 }
108 void refreshServerListNexuizServerList(entity me, float mode)
109 {
110         // 0: just reparametrize
111         // 1: also ask for new servers
112         // 2: clear
113         print("refresh of type ", ftos(mode), "\n");
114         /* if(mode == 2) // borken
115         {
116                 // clear list
117                 localcmd("net_slist\n");
118                 me.needsRefresh = 1; // net_slist kills sort order, so we need to restore it later
119         }
120         else */
121         {
122                 float m;
123                 m = SLIST_MASK_AND;
124                 resethostcachemasks();
125                 if(!me.filterShowFull)
126                         sethostcachemasknumber(m++, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL);
127                 if(!me.filterShowEmpty)
128                         sethostcachemasknumber(m++, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
129                 sethostcachesort(me.currentSortField, me.currentSortOrder < 0);
130                 resorthostcache();
131                 if(mode >= 1)
132                         refreshhostcache();
133         }
134 }
135 void focusEnterNexuizServerList(entity me)
136 {
137         if(time < me.nextRefreshTime)
138         {
139                 print("sorry, no refresh yet\n");
140                 return;
141         }
142         me.nextRefreshTime = time + 10;
143         me.refreshServerList(me, 1);
144 }
145 void drawNexuizServerList(entity me)
146 {
147         float i, found;
148
149         if(me.currentSortField == -1)
150         {
151                 me.setSortOrder(me, SLIST_FIELD_PING, +1);
152                 me.refreshServerList(me, 2);
153         }
154         else if(me.needsRefresh == 1)
155         {
156                 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
157         }
158         else if(me.needsRefresh == 2)
159         {
160                 me.needsRefresh = 0;
161                 me.refreshServerList(me, 0);
162         }
163
164         me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
165         me.connectButton.disabled = (me.nItems == 0);
166
167         found = 0;
168         if(me.selectedServer)
169         {
170                 for(i = 0; i < me.nItems; ++i)
171                         if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
172                         {
173                                 if(i != me.selectedItem)
174                                 {
175                                         me.lastClickedServer = -1;
176                                         me.selectedItem = i;
177                                 }
178                                 found = 1;
179                                 break;
180                         }
181         }
182         if(!found)
183                 if(me.nItems > 0)
184                 {
185                         if(me.selectedItem >= me.nItems)
186                                 me.selectedItem = me.nItems - 1;
187                         if(me.selectedServer)
188                                 strunzone(me.selectedServer);
189                         me.selectedServer = strzone(gethostcachestring(SLIST_FIELD_CNAME, me.selectedItem));
190                 }
191
192         drawListBox(me);
193 }
194 void ServerList_PingSort_Click(entity btn, entity me)
195 {
196         me.setSortOrder(me, SLIST_FIELD_PING, +1);
197 }
198 void ServerList_NameSort_Click(entity btn, entity me)
199 {
200         me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
201 }
202 void ServerList_MapSort_Click(entity btn, entity me)
203 {
204         me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
205 }
206 void ServerList_PlayerSort_Click(entity btn, entity me)
207 {
208         me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
209 }
210 void ServerList_ShowEmpty_Click(entity box, entity me)
211 {
212         box.checked = me.filterShowEmpty = !me.filterShowEmpty;
213         me.refreshServerList(me, 0);
214 }
215 void ServerList_ShowFull_Click(entity box, entity me)
216 {
217         box.checked = me.filterShowFull = !me.filterShowFull;
218         me.refreshServerList(me, 0);
219 }
220 void setSortOrderNexuizServerList(entity me, float field, float direction)
221 {
222         if(me.currentSortField == field)
223                 direction = -me.currentSortOrder;
224         me.currentSortOrder = direction;
225         me.currentSortField = field;
226         me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);
227         me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);
228         me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);
229         me.sortButton4.forcePressed = (field == SLIST_FIELD_NUMHUMANS);
230         me.selectedItem = 0;
231         if(me.selectedServer)
232                 strunzone(me.selectedServer);
233         me.selectedServer = string_null;
234         me.refreshServerList(me, 0);
235 }
236 void positionSortButtonNexuizServerList(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
237 {
238         vector originInLBSpace, sizeInLBSpace;
239         originInLBSpace = eY * (-me.itemHeight);
240         sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
241
242         vector originInDialogSpace, sizeInDialogSpace;
243         originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
244         sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
245
246         btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
247         btn.Container_size_x   =                         sizeInDialogSpace_x * theSize;
248         btn.setText(btn, theTitle);
249         btn.onClick = theFunc;
250         btn.onClickEntity = me;
251         btn.resized = 1;
252 }
253 void resizeNotifyNexuizServerList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
254 {
255         resizeNotifyNexuizListBox(me, relOrigin, relSize, absOrigin, absSize);
256
257         me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
258         me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
259         me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
260
261         me.columnPingOrigin = 0;
262         me.columnPingSize = me.realFontSize_x * 4;
263         me.columnMapSize = me.realFontSize_x * 12;
264         me.columnPlayersSize = me.realFontSize_x * 6;
265         me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - 3 * me.realFontSize_x;
266         me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
267         me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
268         me.columnPlayersOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
269
270         me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, "Ping", ServerList_PingSort_Click);
271         me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, "Host name", ServerList_NameSort_Click);
272         me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, "Map", ServerList_MapSort_Click);
273         me.positionSortButton(me, me.sortButton4, me.columnPlayersOrigin, me.columnPlayersSize, "Players", ServerList_PlayerSort_Click);
274
275         float f;
276         f = me.currentSortField;
277         me.currentSortField = -1;
278         me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
279 }
280 void ServerList_Connect_Click(entity btn, entity me)
281 {
282         if(me.nItems > 0)
283                 localcmd("connect ", me.selectedServer, "\n");
284 }
285 void clickListBoxItemNexuizServerList(entity me, float i, vector where)
286 {
287         if(i == me.lastClickedServer)
288                 if(time < me.lastClickedTime + 0.3)
289                 {
290                         // DOUBLE CLICK!
291                         ServerList_Connect_Click(NULL, me);
292                 }
293         me.lastClickedServer = i;
294         me.lastClickedTime = time;
295 }
296 void drawListBoxItemNexuizServerList(entity me, float i, vector absSize, float isSelected)
297 {
298         // layout: Ping, Server name, Map name, NP, TP, MP
299         string s;
300         float p;
301         vector theColor;
302         float theAlpha;
303
304         if(isSelected)
305                 draw_Fill('0 0 0', '1 1 0', '0 0 1', 0.5);
306
307         if(gethostcachenumber(SLIST_FIELD_NUMPLAYERS, i) >= gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))
308                 theAlpha = 0.2;
309         else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
310                 theAlpha = 0.5;
311         else
312                 theAlpha = 1;
313         
314         p = gethostcachenumber(SLIST_FIELD_PING, i);
315         if(p < 50)
316                 theColor = eX * (p / 50) + eY;
317         else if(p < 150)
318                 theColor = eX + eY * ((150 - p) / 100);
319         else if(p < 650)
320         {
321                 theColor = eX;
322                 theAlpha *= 0.1 + 0.9 * (650 - p) / 500;
323         }
324         else
325         {
326                 theColor = eX;
327                 theAlpha *= 0.1;
328         }
329         
330         s = ftos(p);
331         draw_Text(me.realUpperMargin * eY + (me.columnPingSize - draw_TextWidth(s, 0) * me.realFontSize_x) * eX, s, me.realFontSize, theColor, theAlpha, 0);
332         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize / me.realFontSize_x, 0);
333         draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha, 0);
334         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize / me.realFontSize_x, 0);
335         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);
336         s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
337         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);
338 }
339 #endif