]> icculus.org git repositories - divverent/nexuiz.git/blob - data/qcsrc/menu-div0test/nexuiz/serverlist.c
add empty/full filters
[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                 resethostcachemasks();
124                 if(!me.filterShowEmpty)
125                         sethostcachemasknumber(SLIST_MASK_AND + 0, SLIST_FIELD_NUMHUMANS, 1, SLIST_TEST_GREATEREQUAL);
126                 if(!me.filterShowFull)
127                         sethostcachemasknumber(SLIST_MASK_AND + 1, SLIST_FIELD_FREESLOTS, 1, SLIST_TEST_GREATEREQUAL);
128                 sethostcachesort(me.currentSortField, me.currentSortOrder < 0);
129                 resorthostcache();
130                 if(mode >= 1)
131                         refreshhostcache();
132         }
133 }
134 void focusEnterNexuizServerList(entity me)
135 {
136         if(time < me.nextRefreshTime)
137         {
138                 print("sorry, no refresh yet\n");
139                 return;
140         }
141         me.nextRefreshTime = time + 60;
142         me.refreshServerList(me, 1);
143 }
144 void drawNexuizServerList(entity me)
145 {
146         float i;
147
148         if(me.currentSortField == -1)
149         {
150                 me.setSortOrder(me, SLIST_FIELD_PING, +1);
151                 me.refreshServerList(me, 2);
152         }
153         else if(me.needsRefresh == 1)
154         {
155                 me.needsRefresh = 2; // delay by one frame to make sure "slist" has been executed
156         }
157         else if(me.needsRefresh == 2)
158         {
159                 me.needsRefresh = 0;
160                 me.refreshServerList(me, 0);
161         }
162
163         me.nItems = gethostcachevalue(SLIST_HOSTCACHEVIEWCOUNT);
164         me.connectButton.disabled = (me.nItems == 0);
165         for(i = 0; i < me.nItems; ++i)
166                 if(gethostcachestring(SLIST_FIELD_CNAME, i) == me.selectedServer)
167                 {
168                         if(i != me.selectedItem)
169                         {
170                                 me.lastClickedServer = -1;
171                                 me.selectedItem = i;
172                         }
173                         break;
174                 }
175         drawListBox(me);
176 }
177 void ServerList_PingSort_Click(entity btn, entity me)
178 {
179         me.setSortOrder(me, SLIST_FIELD_PING, +1);
180 }
181 void ServerList_NameSort_Click(entity btn, entity me)
182 {
183         me.setSortOrder(me, SLIST_FIELD_NAME, -1); // why?
184 }
185 void ServerList_MapSort_Click(entity btn, entity me)
186 {
187         me.setSortOrder(me, SLIST_FIELD_MAP, -1); // why?
188 }
189 void ServerList_PlayerSort_Click(entity btn, entity me)
190 {
191         me.setSortOrder(me, SLIST_FIELD_NUMHUMANS, -1);
192 }
193 void ServerList_ShowEmpty_Click(entity box, entity me)
194 {
195         box.checked = me.filterShowEmpty = !me.filterShowEmpty;
196         me.refreshServerList(me, 0);
197 }
198 void ServerList_ShowFull_Click(entity box, entity me)
199 {
200         box.checked = me.filterShowFull = !me.filterShowFull;
201         me.refreshServerList(me, 0);
202 }
203 void setSortOrderNexuizServerList(entity me, float field, float direction)
204 {
205         if(me.currentSortField == field)
206                 direction = -me.currentSortOrder;
207         me.currentSortOrder = direction;
208         me.currentSortField = field;
209         me.needsRefresh = 1;
210         me.sortButton1.forcePressed = (field == SLIST_FIELD_PING);
211         me.sortButton2.forcePressed = (field == SLIST_FIELD_NAME);
212         me.sortButton3.forcePressed = (field == SLIST_FIELD_MAP);
213         me.sortButton4.forcePressed = (field == SLIST_FIELD_NUMHUMANS);
214         me.selectedItem = 0;
215         if(me.selectedServer)
216                 strunzone(me.selectedServer);
217         me.selectedServer = string_null;
218 }
219 void positionSortButtonNexuizServerList(entity me, entity btn, float theOrigin, float theSize, string theTitle, void(entity, entity) theFunc)
220 {
221         vector originInLBSpace, sizeInLBSpace;
222         originInLBSpace = eY * (-me.itemHeight);
223         sizeInLBSpace = eY * me.itemHeight + eX * (1 - me.controlWidth);
224
225         vector originInDialogSpace, sizeInDialogSpace;
226         originInDialogSpace = boxToGlobal(originInLBSpace, me.Container_origin, me.Container_size);
227         sizeInDialogSpace = boxToGlobalSize(sizeInLBSpace, me.Container_size);
228
229         btn.Container_origin_x = originInDialogSpace_x + sizeInDialogSpace_x * theOrigin;
230         btn.Container_size_x   =                         sizeInDialogSpace_x * theSize;
231         btn.setText(btn, theTitle);
232         btn.onClick = theFunc;
233         btn.onClickEntity = me;
234         btn.resized = 1;
235 }
236 void resizeNotifyNexuizServerList(entity me, vector relOrigin, vector relSize, vector absOrigin, vector absSize)
237 {
238         resizeNotifyNexuizListBox(me, relOrigin, relSize, absOrigin, absSize);
239
240         me.realFontSize_y = me.fontSize / (absSize_y * me.itemHeight);
241         me.realFontSize_x = me.fontSize / (absSize_x * (1 - me.controlWidth));
242         me.realUpperMargin = 0.5 * (1 - me.realFontSize_y);
243
244         me.columnPingOrigin = 0;
245         me.columnPingSize = me.realFontSize_x * 4;
246         me.columnMapSize = me.realFontSize_x * 12;
247         me.columnPlayersSize = me.realFontSize_x * 6;
248         me.columnNameSize = 1 - me.columnPlayersSize - me.columnMapSize - me.columnPingSize - 3 * me.realFontSize_x;
249         me.columnNameOrigin = me.columnPingOrigin + me.columnPingSize + me.realFontSize_x;
250         me.columnMapOrigin = me.columnNameOrigin + me.columnNameSize + me.realFontSize_x;
251         me.columnPlayersOrigin = me.columnMapOrigin + me.columnMapSize + me.realFontSize_x;
252
253         me.positionSortButton(me, me.sortButton1, me.columnPingOrigin, me.columnPingSize, "Ping", ServerList_PingSort_Click);
254         me.positionSortButton(me, me.sortButton2, me.columnNameOrigin, me.columnNameSize, "Host name", ServerList_NameSort_Click);
255         me.positionSortButton(me, me.sortButton3, me.columnMapOrigin, me.columnMapSize, "Map", ServerList_MapSort_Click);
256         me.positionSortButton(me, me.sortButton4, me.columnPlayersOrigin, me.columnPlayersSize, "Players", ServerList_PlayerSort_Click);
257
258         float f;
259         f = me.currentSortField;
260         me.currentSortField = -1;
261         me.setSortOrder(me, f, me.currentSortOrder); // force resetting the sort order
262 }
263 void ServerList_Connect_Click(entity btn, entity me)
264 {
265         if(me.nItems > 0)
266                 localcmd("connect ", me.selectedServer, "\n");
267 }
268 void ServerList_Refresh_Click(entity btn, entity me)
269 {
270         refreshhostcache();
271 }
272 void clickListBoxItemNexuizServerList(entity me, float i, vector where)
273 {
274         if(i == me.lastClickedServer)
275                 if(time < me.lastClickedTime + 0.3)
276                 {
277                         // DOUBLE CLICK!
278                         ServerList_Connect_Click(NULL, me);
279                 }
280         me.lastClickedServer = i;
281         me.lastClickedTime = time;
282 }
283 void drawListBoxItemNexuizServerList(entity me, float i, vector absSize, float isSelected)
284 {
285         // layout: Ping, Server name, Map name, NP, TP, MP
286         string s;
287         float p;
288         vector theColor;
289         float theAlpha;
290
291         if(isSelected)
292                 draw_Fill('0 0 0', '1 1 0', '0 0 1', 0.5);
293
294         if(gethostcachenumber(SLIST_FIELD_NUMPLAYERS, i) >= gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i))
295                 theAlpha = 0.2;
296         else if not(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i))
297                 theAlpha = 0.5;
298         else
299                 theAlpha = 1;
300         
301         p = gethostcachenumber(SLIST_FIELD_PING, i);
302         if(p < 50)
303                 theColor = eX * (p / 50) + eY;
304         else if(p < 150)
305                 theColor = eX + eY * ((150 - p) / 100);
306         else if(p < 650)
307         {
308                 theColor = eX;
309                 theAlpha *= 0.1 + 0.9 * (650 - p) / 500;
310         }
311         else
312         {
313                 theColor = eX;
314                 theAlpha *= 0.1;
315         }
316         
317         s = ftos(p);
318         draw_Text(me.realUpperMargin * eY + (me.columnPingSize - draw_TextWidth(s) * me.realFontSize_x) * eX, s, me.realFontSize, theColor, theAlpha);
319         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_NAME, i), me.columnNameSize / me.realFontSize_x);
320         draw_Text(me.realUpperMargin * eY + me.columnNameOrigin * eX, s, me.realFontSize, theColor, theAlpha);
321         s = draw_TextShortenToWidth(gethostcachestring(SLIST_FIELD_MAP, i), me.columnMapSize / me.realFontSize_x);
322         draw_Text(me.realUpperMargin * eY + (me.columnMapOrigin + (me.columnMapSize - draw_TextWidth(s) * me.realFontSize_x) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha);
323         s = strcat(ftos(gethostcachenumber(SLIST_FIELD_NUMHUMANS, i)), "/", ftos(gethostcachenumber(SLIST_FIELD_MAXPLAYERS, i)));
324         draw_Text(me.realUpperMargin * eY + (me.columnPlayersOrigin + (me.columnPlayersSize - draw_TextWidth(s) * me.realFontSize_x) * 0.5) * eX, s, me.realFontSize, theColor, theAlpha);
325 }
326 #endif