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