Merge branch 'master' into martin-t/limit
[xonotic/xonotic-data.pk3dir.git] / qcsrc / client / hud / hud_config.qc
1 #include "hud_config.qh"
2
3 #include "hud.qh"
4 #include "panel/scoreboard.qh"
5 #include <client/autocvars.qh>
6 #include <client/defs.qh>
7 #include <client/miscfunctions.qh>
8 #include <client/view.qh>
9
10 #define HUD_Write(s) fputs(fh, s)
11 #define HUD_Write_Cvar(cvar) HUD_Write(strcat("seta ", cvar, " \"", cvar_string(cvar), "\"\n"))
12 #define HUD_Write_PanelCvar(cvar_suf) str = strcat("hud_panel_", panel.panel_name, cvar_suf), HUD_Write_Cvar(str)
13 // Save the config
14 void HUD_Panel_ExportCfg(string cfgname)
15 {
16         float fh;
17         string filename = strcat("hud_", autocvar_hud_skin, "_", cfgname, ".cfg");
18         string str = "";
19         fh = fopen(filename, FILE_WRITE);
20         if(fh >= 0)
21         {
22                 HUD_Write("//title \n");
23                 HUD_Write("//author \n");
24                 HUD_Write("\n");
25                 HUD_Write_Cvar("hud_skin");
26                 HUD_Write_Cvar("hud_panel_bg");
27                 HUD_Write_Cvar("hud_panel_bg_color");
28                 HUD_Write_Cvar("hud_panel_bg_color_team");
29                 HUD_Write_Cvar("hud_panel_bg_alpha");
30                 HUD_Write_Cvar("hud_panel_bg_border");
31                 HUD_Write_Cvar("hud_panel_bg_padding");
32                 HUD_Write_Cvar("hud_panel_fg_alpha");
33                 HUD_Write("\n");
34
35                 HUD_Write_Cvar("hud_dock");
36                 HUD_Write_Cvar("hud_dock_color");
37                 HUD_Write_Cvar("hud_dock_color_team");
38                 HUD_Write_Cvar("hud_dock_alpha");
39                 HUD_Write("\n");
40
41                 HUD_Write_Cvar("hud_progressbar_alpha");
42                 HUD_Write_Cvar("hud_progressbar_strength_color");
43                 HUD_Write_Cvar("hud_progressbar_superweapons_color");
44                 HUD_Write_Cvar("hud_progressbar_shield_color");
45                 HUD_Write_Cvar("hud_progressbar_health_color");
46                 HUD_Write_Cvar("hud_progressbar_armor_color");
47                 HUD_Write_Cvar("hud_progressbar_fuel_color");
48                 HUD_Write_Cvar("hud_progressbar_oxygen_color");
49                 HUD_Write_Cvar("hud_progressbar_nexball_color");
50                 HUD_Write_Cvar("hud_progressbar_speed_color");
51                 HUD_Write_Cvar("hud_progressbar_acceleration_color");
52                 HUD_Write_Cvar("hud_progressbar_acceleration_neg_color");
53                 HUD_Write_Cvar("hud_progressbar_vehicles_ammo1_color");
54                 HUD_Write_Cvar("hud_progressbar_vehicles_ammo2_color");
55                 HUD_Write("\n");
56
57                 HUD_Write_Cvar("_hud_panelorder");
58                 HUD_Write("\n");
59
60                 HUD_Write_Cvar("hud_configure_grid");
61                 HUD_Write_Cvar("hud_configure_grid_xsize");
62                 HUD_Write_Cvar("hud_configure_grid_ysize");
63                 HUD_Write("\n");
64
65                 // common cvars for all panels
66                 for (int i = 0; i < hud_panels_COUNT; ++i)
67                 {
68                         panel = hud_panels_from(i);
69
70                         HUD_Write_PanelCvar("_pos");
71                         HUD_Write_PanelCvar("_size");
72                         HUD_Write_PanelCvar("_bg");
73                         HUD_Write_PanelCvar("_bg_color");
74                         HUD_Write_PanelCvar("_bg_color_team");
75                         HUD_Write_PanelCvar("_bg_alpha");
76                         HUD_Write_PanelCvar("_bg_border");
77                         HUD_Write_PanelCvar("_bg_padding");
78                         switch(panel) {
79                                 case HUD_PANEL_WEAPONS:
80                                         HUD_Write_Cvar("hud_panel_weapons_accuracy");
81                                         HUD_Write_Cvar("hud_panel_weapons_label");
82                                         HUD_Write_Cvar("hud_panel_weapons_label_scale");
83                                         HUD_Write_Cvar("hud_panel_weapons_complainbubble");
84                                         HUD_Write_Cvar("hud_panel_weapons_complainbubble_padding");
85                                         HUD_Write_Cvar("hud_panel_weapons_complainbubble_time");
86                                         HUD_Write_Cvar("hud_panel_weapons_complainbubble_fadetime");
87                                         HUD_Write_Cvar("hud_panel_weapons_complainbubble_color_outofammo");
88                                         HUD_Write_Cvar("hud_panel_weapons_complainbubble_color_donthave");
89                                         HUD_Write_Cvar("hud_panel_weapons_complainbubble_color_unavailable");
90                                         HUD_Write_Cvar("hud_panel_weapons_ammo");
91                                         HUD_Write_Cvar("hud_panel_weapons_ammo_color");
92                                         HUD_Write_Cvar("hud_panel_weapons_ammo_alpha");
93                                         HUD_Write_Cvar("hud_panel_weapons_aspect");
94                                         HUD_Write_Cvar("hud_panel_weapons_timeout");
95                                         HUD_Write_Cvar("hud_panel_weapons_timeout_effect");
96                                         HUD_Write_Cvar("hud_panel_weapons_timeout_fadebgmin");
97                                         HUD_Write_Cvar("hud_panel_weapons_timeout_fadefgmin");
98                                         HUD_Write_Cvar("hud_panel_weapons_timeout_speed_in");
99                                         HUD_Write_Cvar("hud_panel_weapons_timeout_speed_out");
100                                         HUD_Write_Cvar("hud_panel_weapons_onlyowned");
101                                         HUD_Write_Cvar("hud_panel_weapons_orderbyimpulse");
102                                         HUD_Write_Cvar("hud_panel_weapons_noncurrent_alpha");
103                                         HUD_Write_Cvar("hud_panel_weapons_noncurrent_scale");
104                                         HUD_Write_Cvar("hud_panel_weapons_selection_radius");
105                                         HUD_Write_Cvar("hud_panel_weapons_selection_speed");
106                                         break;
107                                 case HUD_PANEL_AMMO:
108                                         HUD_Write_Cvar("hud_panel_ammo_onlycurrent");
109                                         HUD_Write_Cvar("hud_panel_ammo_noncurrent_alpha");
110                                         HUD_Write_Cvar("hud_panel_ammo_noncurrent_scale");
111                                         HUD_Write_Cvar("hud_panel_ammo_iconalign");
112                                         HUD_Write_Cvar("hud_panel_ammo_progressbar");
113                                         HUD_Write_Cvar("hud_panel_ammo_progressbar_name");
114                                         HUD_Write_Cvar("hud_panel_ammo_progressbar_xoffset");
115                                         HUD_Write_Cvar("hud_panel_ammo_text");
116                                         break;
117                                 case HUD_PANEL_POWERUPS:
118                                         HUD_Write_Cvar("hud_panel_powerups_iconalign");
119                                         HUD_Write_Cvar("hud_panel_powerups_baralign");
120                                         HUD_Write_Cvar("hud_panel_powerups_progressbar");
121                                         HUD_Write_Cvar("hud_panel_powerups_text");
122                                         break;
123                                 case HUD_PANEL_HEALTHARMOR:
124                                         HUD_Write_Cvar("hud_panel_healtharmor_combined");
125                                         HUD_Write_Cvar("hud_panel_healtharmor_flip");
126                                         HUD_Write_Cvar("hud_panel_healtharmor_iconalign");
127                                         HUD_Write_Cvar("hud_panel_healtharmor_baralign");
128                                         HUD_Write_Cvar("hud_panel_healtharmor_progressbar");
129                                         HUD_Write_Cvar("hud_panel_healtharmor_progressbar_health");
130                                         HUD_Write_Cvar("hud_panel_healtharmor_progressbar_armor");
131                                         HUD_Write_Cvar("hud_panel_healtharmor_progressbar_gfx");
132                                         HUD_Write_Cvar("hud_panel_healtharmor_progressbar_gfx_smooth");
133                                         HUD_Write_Cvar("hud_panel_healtharmor_text");
134                                         break;
135                                 case HUD_PANEL_NOTIFY:
136                                         HUD_Write_Cvar("hud_panel_notify_flip");
137                                         HUD_Write_Cvar("hud_panel_notify_fontsize");
138                                         HUD_Write_Cvar("hud_panel_notify_time");
139                                         HUD_Write_Cvar("hud_panel_notify_fadetime");
140                                         HUD_Write_Cvar("hud_panel_notify_icon_aspect");
141                                         break;
142                                 case HUD_PANEL_TIMER:
143                                         break;
144                                 case HUD_PANEL_RADAR:
145                                         HUD_Write_Cvar("hud_panel_radar_foreground_alpha");
146                                         HUD_Write_Cvar("hud_panel_radar_rotation");
147                                         HUD_Write_Cvar("hud_panel_radar_zoommode");
148                                         HUD_Write_Cvar("hud_panel_radar_scale");
149                                         HUD_Write_Cvar("hud_panel_radar_maximized_scale");
150                                         HUD_Write_Cvar("hud_panel_radar_maximized_size");
151                                         HUD_Write_Cvar("hud_panel_radar_maximized_rotation");
152                                         HUD_Write_Cvar("hud_panel_radar_maximized_zoommode");
153                                         break;
154                                 case HUD_PANEL_SCORE:
155                                         HUD_Write_Cvar("hud_panel_score_rankings");
156                                         break;
157                                 case HUD_PANEL_VOTE:
158                                         HUD_Write_Cvar("hud_panel_vote_alreadyvoted_alpha");
159                                         break;
160                                 case HUD_PANEL_MODICONS:
161                                         HUD_Write_Cvar("hud_panel_modicons_ca_layout");
162                                         HUD_Write_Cvar("hud_panel_modicons_dom_layout");
163                                         HUD_Write_Cvar("hud_panel_modicons_freezetag_layout");
164                                         break;
165                                 case HUD_PANEL_PRESSEDKEYS:
166                                         HUD_Write_Cvar("hud_panel_pressedkeys_aspect");
167                                         HUD_Write_Cvar("hud_panel_pressedkeys_attack");
168                                         break;
169                                 case HUD_PANEL_ENGINEINFO:
170                                         HUD_Write_Cvar("hud_panel_engineinfo_framecounter_time");
171                                         HUD_Write_Cvar("hud_panel_engineinfo_framecounter_decimals");
172                                         break;
173                                 case HUD_PANEL_INFOMESSAGES:
174                                         HUD_Write_Cvar("hud_panel_infomessages_flip");
175                                         break;
176                                 case HUD_PANEL_PHYSICS:
177                                         HUD_Write_Cvar("hud_panel_physics_speed_unit_show");
178                                         HUD_Write_Cvar("hud_panel_physics_speed_max");
179                                         HUD_Write_Cvar("hud_panel_physics_speed_vertical");
180                                         HUD_Write_Cvar("hud_panel_physics_topspeed");
181                                         HUD_Write_Cvar("hud_panel_physics_topspeed_time");
182                                         HUD_Write_Cvar("hud_panel_physics_acceleration_max");
183                                         HUD_Write_Cvar("hud_panel_physics_acceleration_vertical");
184                                         HUD_Write_Cvar("hud_panel_physics_flip");
185                                         HUD_Write_Cvar("hud_panel_physics_baralign");
186                                         HUD_Write_Cvar("hud_panel_physics_progressbar");
187                                         HUD_Write_Cvar("hud_panel_physics_acceleration_progressbar_mode");
188                                         HUD_Write_Cvar("hud_panel_physics_acceleration_progressbar_scale");
189                                         HUD_Write_Cvar("hud_panel_physics_acceleration_progressbar_nonlinear");
190                                         HUD_Write_Cvar("hud_panel_physics_text");
191                                         HUD_Write_Cvar("hud_panel_physics_text_scale");
192                                         break;
193                                 case HUD_PANEL_CENTERPRINT:
194                                         HUD_Write_Cvar("hud_panel_centerprint_align");
195                                         HUD_Write_Cvar("hud_panel_centerprint_flip");
196                                         HUD_Write_Cvar("hud_panel_centerprint_fontscale");
197                                         HUD_Write_Cvar("hud_panel_centerprint_time");
198                                         HUD_Write_Cvar("hud_panel_centerprint_fade_in");
199                                         HUD_Write_Cvar("hud_panel_centerprint_fade_out");
200                                         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent");
201                                         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent_passone");
202                                         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent_passone_minalpha");
203                                         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent_passtwo");
204                                         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent_passtwo_minalpha");
205                                         HUD_Write_Cvar("hud_panel_centerprint_fade_subsequent_minfontsize");
206                                         HUD_Write_Cvar("hud_panel_centerprint_fade_minfontsize");
207                                         break;
208                                 case HUD_PANEL_ITEMSTIME:
209                                         HUD_Write_Cvar("hud_panel_itemstime_iconalign");
210                                         HUD_Write_Cvar("hud_panel_itemstime_progressbar");
211                                         HUD_Write_Cvar("hud_panel_itemstime_progressbar_name");
212                                         HUD_Write_Cvar("hud_panel_itemstime_progressbar_reduced");
213                                         HUD_Write_Cvar("hud_panel_itemstime_text");
214                                         HUD_Write_Cvar("hud_panel_itemstime_ratio");
215                                         HUD_Write_Cvar("hud_panel_itemstime_dynamicsize");
216                                         break;
217                                 case HUD_PANEL_MAPVOTE:
218                                         HUD_Write_Cvar("hud_panel_mapvote_highlight_border");
219                                         break;
220                                 case HUD_PANEL_QUICKMENU:
221                                         HUD_Write_Cvar("hud_panel_quickmenu_align");
222                                         break;
223                                 case HUD_PANEL_SCOREBOARD:
224                                         HUD_Write_Cvar("hud_panel_scoreboard_fadeinspeed");
225                                         HUD_Write_Cvar("hud_panel_scoreboard_fadeoutspeed");
226                                         HUD_Write_Cvar("hud_panel_scoreboard_respawntime_decimals");
227                                         HUD_Write_Cvar("hud_panel_scoreboard_table_bg_alpha");
228                                         HUD_Write_Cvar("hud_panel_scoreboard_table_bg_scale");
229                                         HUD_Write_Cvar("hud_panel_scoreboard_table_fg_alpha");
230                                         HUD_Write_Cvar("hud_panel_scoreboard_table_fg_alpha_self");
231                                         HUD_Write_Cvar("hud_panel_scoreboard_table_highlight");
232                                         HUD_Write_Cvar("hud_panel_scoreboard_table_highlight_alpha");
233                                         HUD_Write_Cvar("hud_panel_scoreboard_table_highlight_alpha_self");
234                                         HUD_Write_Cvar("hud_panel_scoreboard_bg_teams_color_team");
235                                         HUD_Write_Cvar("hud_panel_scoreboard_accuracy_doublerows");
236                                         HUD_Write_Cvar("hud_panel_scoreboard_accuracy_nocolors");
237                                         break;
238                         }
239                         HUD_Write("\n");
240                 }
241                 MUTATOR_CALLHOOK(HUD_WriteCvars, fh);
242
243                 HUD_Write("menu_sync\n"); // force the menu to reread the cvars, so that the dialogs are updated
244
245                 LOG_INFOF(_("^2Successfully exported to %s! (Note: It's saved in data/data/)"), filename);
246                 fclose(fh);
247         }
248         else
249                 LOG_INFOF(_("^1Couldn't write to %s"), filename);
250 }
251
252 void HUD_Configure_Exit_Force()
253 {
254         if (hud_configure_menu_open)
255         {
256                 hud_configure_menu_open = 0;
257                 localcmd("togglemenu\n");
258         }
259         cursor_type = CURSOR_NORMAL;
260         cvar_set("_hud_configure", "0");
261 }
262
263 // check if move will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
264 vector HUD_Panel_CheckMove(vector myPos, vector mySize)
265 {
266         vector myCenter, targCenter;
267         vector myTarget = myPos;
268         int i;
269         for (i = 0; i < hud_panels_COUNT; ++i) {
270                 panel = hud_panels_from(i);
271                 if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
272                 if(panel == highlightedPanel) continue;
273                 HUD_Panel_UpdatePosSize();
274                 if(!panel_enabled) continue;
275
276                 panel_pos -= '1 1 0' * panel_bg_border;
277                 panel_size += '2 2 0' * panel_bg_border;
278
279                 if(myPos.y + mySize.y < panel_pos.y)
280                         continue;
281                 if(myPos.y > panel_pos.y + panel_size.y)
282                         continue;
283
284                 if(myPos.x + mySize.x < panel_pos.x)
285                         continue;
286                 if(myPos.x > panel_pos.x + panel_size.x)
287                         continue;
288
289                 // OK, there IS a collision.
290
291                 myCenter.x = myPos.x + 0.5 * mySize.x;
292                 myCenter.y = myPos.y + 0.5 * mySize.y;
293
294                 targCenter.x = panel_pos.x + 0.5 * panel_size.x;
295                 targCenter.y = panel_pos.y + 0.5 * panel_size.y;
296
297                 if(myCenter.x < targCenter.x && myCenter.y < targCenter.y) // top left (of the target panel)
298                 {
299                         if(myPos.x + mySize.x - panel_pos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
300                                 myTarget.x = panel_pos.x - mySize.x;
301                         else // push it upwards
302                                 myTarget.y = panel_pos.y - mySize.y;
303                 }
304                 else if(myCenter.x > targCenter.x && myCenter.y < targCenter.y) // top right
305                 {
306                         if(panel_pos.x + panel_size.x - myPos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
307                                 myTarget.x = panel_pos.x + panel_size.x;
308                         else // push it upwards
309                                 myTarget.y = panel_pos.y - mySize.y;
310                 }
311                 else if(myCenter.x < targCenter.x && myCenter.y > targCenter.y) // bottom left
312                 {
313                         if(myPos.x + mySize.x - panel_pos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
314                                 myTarget.x = panel_pos.x - mySize.x;
315                         else // push it downwards
316                                 myTarget.y = panel_pos.y + panel_size.y;
317                 }
318                 else if(myCenter.x > targCenter.x && myCenter.y > targCenter.y) // bottom right
319                 {
320                         if(panel_pos.x + panel_size.x - myPos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
321                                 myTarget.x = panel_pos.x + panel_size.x;
322                         else // push it downwards
323                                 myTarget.y = panel_pos.y + panel_size.y;
324                 }
325                 //if(cvar("hud_configure_checkcollisions_debug"))
326                         //drawfill(panel_pos, panel_size, '1 1 0', .3, DRAWFLAG_NORMAL);
327         }
328
329         return myTarget;
330 }
331
332 void HUD_Panel_SetPos(vector pos)
333 {
334         panel = highlightedPanel;
335         HUD_Panel_UpdatePosSize();
336         vector mySize;
337         mySize = panel_size;
338
339         //if(cvar("hud_configure_checkcollisions_debug"))
340                 //drawfill(pos, mySize, '1 1 1', .2, DRAWFLAG_NORMAL);
341
342         if(autocvar_hud_configure_grid)
343         {
344                 pos.x = floor((pos.x/vid_conwidth)/hud_configure_gridSize.x + 0.5) * hud_configure_realGridSize.x;
345                 pos.y = floor((pos.y/vid_conheight)/hud_configure_gridSize.y + 0.5) * hud_configure_realGridSize.y;
346         }
347
348         if(hud_configure_checkcollisions)
349                 pos = HUD_Panel_CheckMove(pos, mySize);
350
351         pos.x = bound(0, pos.x, vid_conwidth - mySize.x);
352         pos.y = bound(0, pos.y, vid_conheight - mySize.y);
353
354         string s;
355         s = strcat(ftos(pos.x/vid_conwidth), " ", ftos(pos.y/vid_conheight));
356
357         cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
358 }
359
360 // check if resize will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
361 vector HUD_Panel_CheckResize(vector mySize, vector resizeorigin) {
362         vector targEndPos;
363         vector dist;
364         float ratio = mySize.x/mySize.y;
365         int i;
366         for (i = 0; i < hud_panels_COUNT; ++i) {
367                 panel = hud_panels_from(i);
368                 if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
369                 if(panel == highlightedPanel) continue;
370                 HUD_Panel_UpdatePosSize();
371                 if(!panel_enabled) continue;
372
373                 panel_pos -= '1 1 0' * panel_bg_border;
374                 panel_size += '2 2 0' * panel_bg_border;
375
376                 targEndPos = panel_pos + panel_size;
377
378                 // resizeorigin is WITHIN target panel, just abort any collision testing against that particular panel to produce expected behaviour!
379                 if(resizeorigin.x > panel_pos.x && resizeorigin.x < targEndPos.x && resizeorigin.y > panel_pos.y && resizeorigin.y < targEndPos.y)
380                         continue;
381
382                 if (resizeCorner == 1)
383                 {
384                         // check if this panel is on our way
385                         if (resizeorigin.x <= panel_pos.x)
386                                 continue;
387                         if (resizeorigin.y <= panel_pos.y)
388                                 continue;
389                         if (targEndPos.x <= resizeorigin.x - mySize.x)
390                                 continue;
391                         if (targEndPos.y <= resizeorigin.y - mySize.y)
392                                 continue;
393
394                         // there is a collision:
395                         // detect which side of the panel we are facing is actually limiting the resizing
396                         // (which side the resize direction finds for first) and reduce the size up to there
397                         //
398                         // dist is the distance between resizeorigin and the "analogous" point of the panel
399                         // in this case between resizeorigin (bottom-right point) and the bottom-right point of the panel
400                         dist.x = resizeorigin.x - targEndPos.x;
401                         dist.y = resizeorigin.y - targEndPos.y;
402                         if (dist.y <= 0 || dist.x / dist.y > ratio)
403                                 mySize.x = min(mySize.x, dist.x);
404                         else
405                                 mySize.y = min(mySize.y, dist.y);
406                 }
407                 else if (resizeCorner == 2)
408                 {
409                         if (resizeorigin.x >= targEndPos.x)
410                                 continue;
411                         if (resizeorigin.y <= panel_pos.y)
412                                 continue;
413                         if (panel_pos.x >= resizeorigin.x + mySize.x)
414                                 continue;
415                         if (targEndPos.y <= resizeorigin.y - mySize.y)
416                                 continue;
417
418                         dist.x = panel_pos.x - resizeorigin.x;
419                         dist.y = resizeorigin.y - targEndPos.y;
420                         if (dist.y <= 0 || dist.x / dist.y > ratio)
421                                 mySize.x = min(mySize.x, dist.x);
422                         else
423                                 mySize.y = min(mySize.y, dist.y);
424                 }
425                 else if (resizeCorner == 3)
426                 {
427                         if (resizeorigin.x <= panel_pos.x)
428                                 continue;
429                         if (resizeorigin.y >= targEndPos.y)
430                                 continue;
431                         if (targEndPos.x <= resizeorigin.x - mySize.x)
432                                 continue;
433                         if (panel_pos.y >= resizeorigin.y + mySize.y)
434                                 continue;
435
436                         dist.x = resizeorigin.x - targEndPos.x;
437                         dist.y = panel_pos.y - resizeorigin.y;
438                         if (dist.y <= 0 || dist.x / dist.y > ratio)
439                                 mySize.x = min(mySize.x, dist.x);
440                         else
441                                 mySize.y = min(mySize.y, dist.y);
442                 }
443                 else if (resizeCorner == 4)
444                 {
445                         if (resizeorigin.x >= targEndPos.x)
446                                 continue;
447                         if (resizeorigin.y >= targEndPos.y)
448                                 continue;
449                         if (panel_pos.x >= resizeorigin.x + mySize.x)
450                                 continue;
451                         if (panel_pos.y >= resizeorigin.y + mySize.y)
452                                 continue;
453
454                         dist.x = panel_pos.x - resizeorigin.x;
455                         dist.y = panel_pos.y - resizeorigin.y;
456                         if (dist.y <= 0 || dist.x / dist.y > ratio)
457                                 mySize.x = min(mySize.x, dist.x);
458                         else
459                                 mySize.y = min(mySize.y, dist.y);
460                 }
461                 //if(cvar("hud_configure_checkcollisions_debug"))
462                         //drawfill(panel_pos, panel_size, '1 1 0', .3, DRAWFLAG_NORMAL);
463         }
464
465         return mySize;
466 }
467
468 void HUD_Panel_SetPosSize(vector mySize)
469 {
470         panel = highlightedPanel;
471         HUD_Panel_UpdatePosSize();
472         vector resizeorigin = panel_click_resizeorigin;
473         vector myPos;
474
475         // minimum panel size cap
476         mySize.x = max(0.025 * vid_conwidth, mySize.x);
477         mySize.y = max(0.025 * vid_conheight, mySize.y);
478
479         if(highlightedPanel == HUD_PANEL(CHAT)) // some panels have their own restrictions, like the chat panel (which actually only moves the engine chat print around). Looks bad if it's too small.
480         {
481                 mySize.x = max(17 * autocvar_con_chatsize, mySize.x);
482                 mySize.y = max(2 * autocvar_con_chatsize + 2 * panel_bg_padding, mySize.y);
483         }
484
485         // collision testing|
486         // -----------------+
487
488         // we need to know pos at this stage, but it might still change later if we hit a screen edge/other panel (?)
489         if(resizeCorner == 1) {
490                 myPos.x = resizeorigin.x - mySize.x;
491                 myPos.y = resizeorigin.y - mySize.y;
492         } else if(resizeCorner == 2) {
493                 myPos.x = resizeorigin.x;
494                 myPos.y = resizeorigin.y - mySize.y;
495         } else if(resizeCorner == 3) {
496                 myPos.x = resizeorigin.x - mySize.x;
497                 myPos.y = resizeorigin.y;
498         } else { // resizeCorner == 4
499                 myPos.x = resizeorigin.x;
500                 myPos.y = resizeorigin.y;
501         }
502
503         // left/top screen edges
504         if(myPos.x < 0)
505                 mySize.x = mySize.x + myPos.x;
506         if(myPos.y < 0)
507                 mySize.y = mySize.y + myPos.y;
508
509         // bottom/right screen edges
510         if(myPos.x + mySize.x > vid_conwidth)
511                 mySize.x = vid_conwidth - myPos.x;
512         if(myPos.y + mySize.y > vid_conheight)
513                 mySize.y = vid_conheight - myPos.y;
514
515         //if(cvar("hud_configure_checkcollisions_debug"))
516                 //drawfill(myPos, mySize, '1 1 1', .2, DRAWFLAG_NORMAL);
517
518         // before checkresize, otherwise panel can be snapped partially inside another panel or panel aspect ratio can be broken
519         if(autocvar_hud_configure_grid)
520         {
521                 mySize.x = floor((mySize.x/vid_conwidth)/hud_configure_gridSize.x + 0.5) * hud_configure_realGridSize.x;
522                 mySize.y = floor((mySize.y/vid_conheight)/hud_configure_gridSize.y + 0.5) * hud_configure_realGridSize.y;
523         }
524
525         if(hud_configure_checkcollisions)
526                 mySize = HUD_Panel_CheckResize(mySize, resizeorigin);
527
528         // minimum panel size cap, do this once more so we NEVER EVER EVER have a panel smaller than this, JUST IN CASE above code still makes the panel eg negative (impossible to resize back without changing cvars manually then)
529         mySize.x = max(0.025 * vid_conwidth, mySize.x);
530         mySize.y = max(0.025 * vid_conheight, mySize.y);
531
532         // do another pos check, as size might have changed by now
533         if(resizeCorner == 1) {
534                 myPos.x = resizeorigin.x - mySize.x;
535                 myPos.y = resizeorigin.y - mySize.y;
536         } else if(resizeCorner == 2) {
537                 myPos.x = resizeorigin.x;
538                 myPos.y = resizeorigin.y - mySize.y;
539         } else if(resizeCorner == 3) {
540                 myPos.x = resizeorigin.x - mySize.x;
541                 myPos.y = resizeorigin.y;
542         } else { // resizeCorner == 4
543                 myPos.x = resizeorigin.x;
544                 myPos.y = resizeorigin.y;
545         }
546
547         //if(cvar("hud_configure_checkcollisions_debug"))
548                 //drawfill(myPos, mySize, '0 1 0', .3, DRAWFLAG_NORMAL);
549
550         string s;
551         s = strcat(ftos(mySize.x/vid_conwidth), " ", ftos(mySize.y/vid_conheight));
552         cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
553
554         s = strcat(ftos(myPos.x/vid_conwidth), " ", ftos(myPos.y/vid_conheight));
555         cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
556 }
557
558 float pressed_key_time;
559 vector highlightedPanel_initial_pos, highlightedPanel_initial_size;
560 void HUD_Panel_Arrow_Action(float nPrimary)
561 {
562         if(!highlightedPanel)
563                 return;
564
565         hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
566
567         float step;
568         if(autocvar_hud_configure_grid)
569         {
570                 if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
571                 {
572                         if (hudShiftState & S_SHIFT)
573                                 step = hud_configure_realGridSize.y;
574                         else
575                                 step = 2 * hud_configure_realGridSize.y;
576                 }
577                 else
578                 {
579                         if (hudShiftState & S_SHIFT)
580                                 step = hud_configure_realGridSize.x;
581                         else
582                                 step = 2 * hud_configure_realGridSize.x;
583                 }
584         }
585         else
586         {
587                 if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
588                         step = vid_conheight;
589                 else
590                         step = vid_conwidth;
591                 if (hudShiftState & S_SHIFT)
592                         step = (step / 256); // more precision
593                 else
594                         step = (step / 64) * (1 + 2 * (time - pressed_key_time));
595         }
596
597         panel = highlightedPanel;
598         HUD_Panel_UpdatePosSize();
599
600         highlightedPanel_initial_pos = panel_pos;
601         highlightedPanel_initial_size = panel_size;
602
603         if (hudShiftState & S_ALT) // resize
604         {
605                 if(nPrimary == K_UPARROW)
606                         resizeCorner = 1;
607                 else if(nPrimary == K_RIGHTARROW)
608                         resizeCorner = 2;
609                 else if(nPrimary == K_LEFTARROW)
610                         resizeCorner = 3;
611                 else // if(nPrimary == K_DOWNARROW)
612                         resizeCorner = 4;
613
614                 // ctrl+arrow reduces the size, instead of increasing it
615                 // Note that ctrl disables collisions check too, but it's fine
616                 // since we don't collide with anything reducing the size
617                 if (hudShiftState & S_CTRL) {
618                         step = -step;
619                         resizeCorner = 5 - resizeCorner;
620                 }
621
622                 vector mySize;
623                 mySize = panel_size;
624                 panel_click_resizeorigin = panel_pos;
625                 if(resizeCorner == 1) {
626                         panel_click_resizeorigin += mySize;
627                         mySize.y += step;
628                 } else if(resizeCorner == 2) {
629                         panel_click_resizeorigin.y += mySize.y;
630                         mySize.x += step;
631                 } else if(resizeCorner == 3) {
632                         panel_click_resizeorigin.x += mySize.x;
633                         mySize.x += step;
634                 } else { // resizeCorner == 4
635                         mySize.y += step;
636                 }
637                 HUD_Panel_SetPosSize(mySize);
638         }
639         else // move
640         {
641                 vector pos;
642                 pos = panel_pos;
643                 if(nPrimary == K_UPARROW)
644                         pos.y -= step;
645                 else if(nPrimary == K_DOWNARROW)
646                         pos.y += step;
647                 else if(nPrimary == K_LEFTARROW)
648                         pos.x -= step;
649                 else // if(nPrimary == K_RIGHTARROW)
650                         pos.x += step;
651
652                 HUD_Panel_SetPos(pos);
653         }
654
655         panel = highlightedPanel;
656         HUD_Panel_UpdatePosSize();
657
658         if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
659         {
660                 // backup!
661                 panel_pos_backup = highlightedPanel_initial_pos;
662                 panel_size_backup = highlightedPanel_initial_size;
663                 highlightedPanel_backup = highlightedPanel;
664         }
665 }
666
667 entity tab_panels[hud_panels_MAX];
668 entity tab_panel;
669 vector tab_panel_pos;
670 float tab_backward;
671 void reset_tab_panels()
672 {
673         for (int i = 0; i < hud_panels_COUNT; ++i)
674                 tab_panels[i] = NULL;
675 }
676 float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
677 {
678         string s;
679
680         if(bInputType == 2)
681                 return false;
682
683         if(!autocvar__hud_configure)
684                 return false;
685
686         if(bInputType == 3)
687         {
688                 mousepos.x = nPrimary;
689                 mousepos.y = nSecondary;
690                 return true;
691         }
692
693         // block any input while a menu dialog is fading
694         // don't block mousepos read as it leads to cursor jumps in the interaction with the menu
695         if(autocvar__menu_alpha)
696         {
697                 hudShiftState = 0;
698                 mouseClicked = 0;
699                 return true;
700         }
701
702         // allow console bind to work
703         string con_keys = findkeysforcommand("toggleconsole", 0);
704         int keys = tokenize(con_keys); // findkeysforcommand returns data for this
705
706         bool hit_con_bind = false;
707         int i;
708         for (i = 0; i < keys; ++i)
709         {
710                 if(nPrimary == stof(argv(i)))
711                         hit_con_bind = true;
712         }
713
714         if(bInputType == 0) {
715                 if(nPrimary == K_ALT) hudShiftState |= S_ALT;
716                 if(nPrimary == K_CTRL) hudShiftState |= S_CTRL;
717                 if(nPrimary == K_SHIFT) hudShiftState |= S_SHIFT;
718         }
719         else if(bInputType == 1) {
720                 if(nPrimary == K_ALT) hudShiftState -= (hudShiftState & S_ALT);
721                 if(nPrimary == K_CTRL) hudShiftState -= (hudShiftState & S_CTRL);
722                 if(nPrimary == K_SHIFT) hudShiftState -= (hudShiftState & S_SHIFT);
723         }
724
725         if(nPrimary == K_CTRL)
726         {
727                 if (bInputType == 1) //ctrl has been released
728                 {
729                         if (tab_panel)
730                         {
731                                 //switch to selected panel
732                                 highlightedPanel = tab_panel;
733                                 highlightedAction = 0;
734                                 HUD_Panel_FirstInDrawQ(highlightedPanel.panel_id);
735                         }
736                         tab_panel = NULL;
737                         reset_tab_panels();
738                 }
739         }
740
741         if(nPrimary == K_MOUSE1)
742         {
743                 if(bInputType == 0) // key pressed
744                         mouseClicked |= S_MOUSE1;
745                 else if(bInputType == 1) // key released
746                         mouseClicked -= (mouseClicked & S_MOUSE1);
747         }
748         else if(nPrimary == K_MOUSE2)
749         {
750                 if(bInputType == 0) // key pressed
751                         mouseClicked |= S_MOUSE2;
752                 else if(bInputType == 1) // key released
753                         mouseClicked -= (mouseClicked & S_MOUSE2);
754         }
755         else if(nPrimary == K_ESCAPE)
756         {
757                 if (bInputType == 1)
758                         return true;
759                 hud_configure_menu_open = 1;
760                 localcmd("menu_showhudexit\n");
761         }
762         else if(nPrimary == K_BACKSPACE && hudShiftState & S_CTRL)
763         {
764                 if (bInputType == 1)
765                         return true;
766                 if (!hud_configure_menu_open)
767                         HUD_Configure_Exit_Force();
768         }
769         else if(nPrimary == K_TAB && hudShiftState & S_CTRL) // switch panel
770         {
771                 if (bInputType == 1 || mouseClicked)
772                         return true;
773
774                 // FIXME minor bug: if a panel is highlighted, has the same pos_x and
775                 // lays in the same level of another panel then the next consecutive
776                 // CTRL TAB presses will reselect once more the highlighted panel
777
778                 entity starting_panel;
779                 entity old_tab_panel = tab_panel;
780                 if (!tab_panel) //first press of TAB
781                 {
782                         if (highlightedPanel)
783                         {
784                                 panel = highlightedPanel;
785                                 HUD_Panel_UpdatePosSize();
786                         }
787                         else
788                                 panel_pos = '0 0 0';
789                         starting_panel = highlightedPanel;
790                         tab_panel_pos = panel_pos; //to compute level
791                 }
792                 else
793                 {
794                         if ( ((!tab_backward) && (hudShiftState & S_SHIFT)) || (tab_backward && !(hudShiftState & S_SHIFT)) ) //tab direction changed?
795                                 reset_tab_panels();
796                         starting_panel = tab_panel;
797                 }
798                 tab_backward = (hudShiftState & S_SHIFT);
799
800                 float k, level = 0, start_posX;
801                 vector candidate_pos = '0 0 0';
802                 const float LEVELS_NUM = 4;
803                 float level_height = vid_conheight / LEVELS_NUM;
804 LABEL(find_tab_panel)
805                 level = floor(tab_panel_pos.y / level_height) * level_height; //starting level
806                 candidate_pos.x = (!tab_backward) ? vid_conwidth : 0;
807                 start_posX = tab_panel_pos.x;
808                 tab_panel = NULL;
809                 k=0;
810                 while(++k)
811                 {
812                         for(i = 0; i < hud_panels_COUNT; ++i)
813                         {
814                                 panel = hud_panels_from(i);
815                                 if(!(panel.panel_configflags & PANEL_CONFIG_MAIN))
816                                         continue;
817                                 if (panel == tab_panels[i] || panel == starting_panel)
818                                         continue;
819                                 HUD_Panel_UpdatePosSize();
820                                 if (panel_pos.y >= level && (panel_pos.y - level) < level_height)
821                                 if (  ( !tab_backward && panel_pos.x >= start_posX && (panel_pos.x < candidate_pos.x || (panel_pos.x == candidate_pos.x && panel_pos.y <= candidate_pos.y)) )
822                                         || ( tab_backward && panel_pos.x <= start_posX && (panel_pos.x > candidate_pos.x || (panel_pos.x == candidate_pos.x && panel_pos.y >= candidate_pos.y)) )  )
823                                 {
824                                         tab_panel = panel;
825                                         tab_panel_pos = candidate_pos = panel_pos;
826                                 }
827                         }
828                         if (tab_panel)
829                                 break;
830                         if (k == LEVELS_NUM) //tab_panel not found
831                         {
832                                 reset_tab_panels();
833                                 if (!old_tab_panel)
834                                 {
835                                         tab_panel = NULL;
836                                         return true;
837                                 }
838                                 starting_panel = old_tab_panel;
839                                 old_tab_panel = NULL;
840                                 goto find_tab_panel; //u must find tab_panel!
841                         }
842                         if (!tab_backward)
843                         {
844                                 level = (level + level_height) % vid_conheight;
845                                 start_posX = 0;
846                                 candidate_pos.x = vid_conwidth;
847                         }
848                         else
849                         {
850                                 level = (level - level_height) % vid_conheight;
851                                 start_posX = vid_conwidth;
852                                 candidate_pos.x = 0;
853                         }
854                 }
855
856                 tab_panels[tab_panel.panel_id] = tab_panel;
857         }
858         else if(nPrimary == K_SPACE && hudShiftState & S_CTRL) // enable/disable highlighted panel or dock
859         {
860                 if (bInputType == 1 || mouseClicked)
861                         return true;
862
863                 if (highlightedPanel)
864                 {
865                         if(panel.panel_configflags & PANEL_CONFIG_CANBEOFF)
866                                 cvar_set(strcat("hud_panel_", highlightedPanel.panel_name), ftos(!cvar(strcat("hud_panel_", highlightedPanel.panel_name))));
867                 }
868                 else
869                         cvar_set(strcat("hud_dock"), (autocvar_hud_dock == "") ? "dock" : "");
870         }
871         else if(nPrimary == 'c' && hudShiftState & S_CTRL) // copy highlighted panel size
872         {
873                 if (bInputType == 1 || mouseClicked)
874                         return true;
875
876                 if (highlightedPanel)
877                 {
878                         panel = highlightedPanel;
879                         HUD_Panel_UpdatePosSize();
880                         panel_size_copied = panel_size;
881                 }
882         }
883         else if(nPrimary == 'v' && hudShiftState & S_CTRL) // past copied size on the highlighted panel
884         {
885                 if (bInputType == 1 || mouseClicked)
886                         return true;
887
888                 if (panel_size_copied == '0 0 0' || !highlightedPanel)
889                         return true;
890
891                 panel = highlightedPanel;
892                 HUD_Panel_UpdatePosSize();
893
894                 // reduce size if it'd go beyond screen boundaries
895                 vector tmp_size = panel_size_copied;
896                 if (panel_pos.x + panel_size_copied.x > vid_conwidth)
897                         tmp_size.x = vid_conwidth - panel_pos.x;
898                 if (panel_pos.y + panel_size_copied.y > vid_conheight)
899                         tmp_size.y = vid_conheight - panel_pos.y;
900
901                 if (panel_size == tmp_size)
902                         return true;
903
904                 // backup first!
905                 panel_pos_backup = panel_pos;
906                 panel_size_backup = panel_size;
907                 highlightedPanel_backup = highlightedPanel;
908
909                 s = strcat(ftos(tmp_size.x/vid_conwidth), " ", ftos(tmp_size.y/vid_conheight));
910                 cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
911         }
912         else if(nPrimary == 'z' && hudShiftState & S_CTRL) // undo last action
913         {
914                 if (bInputType == 1 || mouseClicked)
915                         return true;
916                 //restore previous values
917                 if (highlightedPanel_backup)
918                 {
919                         s = strcat(ftos(panel_pos_backup.x/vid_conwidth), " ", ftos(panel_pos_backup.y/vid_conheight));
920                         cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_pos"), s);
921                         s = strcat(ftos(panel_size_backup.x/vid_conwidth), " ", ftos(panel_size_backup.y/vid_conheight));
922                         cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_size"), s);
923                         highlightedPanel_backup = NULL;
924                 }
925         }
926         else if(nPrimary == 's' && hudShiftState & S_CTRL) // save config
927         {
928                 if (bInputType == 1 || mouseClicked)
929                         return true;
930                 localcmd("hud save myconfig\n");
931         }
932         else if(nPrimary == K_UPARROW || nPrimary == K_DOWNARROW || nPrimary == K_LEFTARROW || nPrimary == K_RIGHTARROW)
933         {
934                 if (bInputType == 1)
935                 {
936                         pressed_key_time = 0;
937                         return true;
938                 }
939                 else if (pressed_key_time == 0)
940                         pressed_key_time = time;
941
942                 if (!mouseClicked)
943                         HUD_Panel_Arrow_Action(nPrimary); //move or resize panel
944         }
945         else if(nPrimary == K_ENTER || nPrimary == K_SPACE || nPrimary == K_KP_ENTER)
946         {
947                 if (bInputType == 1)
948                         return true;
949                 if (highlightedPanel)
950                         HUD_Panel_EnableMenu();
951         }
952         else if(hit_con_bind || nPrimary == K_PAUSE)
953                 return false;
954
955         return true;
956 }
957
958 int HUD_Panel_Check_Mouse_Pos(bool allow_move)
959 {
960         int i, j = 0;
961         while(j < hud_panels_COUNT)
962         {
963                 i = panel_order[j];
964                 j += 1;
965
966                 panel = hud_panels_from(i);
967                 if(!(panel.panel_configflags & PANEL_CONFIG_MAIN)) continue;
968                 HUD_Panel_UpdatePosSize();
969
970                 float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
971
972                 // move
973                 if(allow_move && mousepos.x > panel_pos.x && mousepos.y > panel_pos.y && mousepos.x < panel_pos.x + panel_size.x && mousepos.y < panel_pos.y + panel_size.y)
974                 {
975                         return CURSOR_MOVE;
976                 }
977                 // resize from topleft border
978                 else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
979                 {
980                         return CURSOR_RESIZE;
981                 }
982                 // resize from topright border
983                 else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
984                 {
985                         return CURSOR_RESIZE2;
986                 }
987                 // resize from bottomleft border
988                 else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + panel_size.y + border)
989                 {
990                         return CURSOR_RESIZE2;
991                 }
992                 // resize from bottomright border
993                 else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + panel_size.y + border)
994                 {
995                         return CURSOR_RESIZE;
996                 }
997         }
998         return CURSOR_NORMAL;
999 }
1000
1001 // move a panel to the beginning of the panel order array (which means it gets drawn last, on top of everything else)
1002 void HUD_Panel_FirstInDrawQ(float id)
1003 {
1004         int i;
1005         int place = -1;
1006         // find out where in the array our current id is, save into place
1007         for(i = 0; i < hud_panels_COUNT; ++i)
1008         {
1009                 if(panel_order[i] == id)
1010                 {
1011                         place = i;
1012                         break;
1013                 }
1014         }
1015         // place last if we didn't find a place for it yet (probably new panel, or screwed up cvar)
1016         if(place == -1)
1017                 place = hud_panels_COUNT - 1;
1018
1019         // move all ids up by one step in the array until "place"
1020         for(i = place; i > 0; --i)
1021         {
1022                 panel_order[i] = panel_order[i-1];
1023         }
1024         // now save the new top id
1025         panel_order[0] = id;
1026
1027         // let's save them into the cvar by some strcat trickery
1028         string s = "";
1029         for(i = 0; i < hud_panels_COUNT; ++i)
1030         {
1031                 s = strcat(s, ftos(panel_order[i]), " ");
1032         }
1033         cvar_set("_hud_panelorder", s);
1034         strcpy(hud_panelorder_prev, autocvar__hud_panelorder); // prevent HUD_Main from doing useless update, we already updated here
1035 }
1036
1037 void HUD_Panel_Highlight(float allow_move)
1038 {
1039         int i, j = 0;
1040
1041         while(j < hud_panels_COUNT)
1042         {
1043                 i = panel_order[j];
1044                 j += 1;
1045
1046                 panel = hud_panels_from(i);
1047                 if(!(panel.panel_configflags & PANEL_CONFIG_MAIN))
1048                         continue;
1049                 HUD_Panel_UpdatePosSize();
1050
1051                 float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
1052
1053                 // move
1054                 if(allow_move && mousepos.x > panel_pos.x && mousepos.y > panel_pos.y && mousepos.x < panel_pos.x + panel_size.x && mousepos.y < panel_pos.y + panel_size.y)
1055                 {
1056                         highlightedPanel = hud_panels_from(i);
1057                         HUD_Panel_FirstInDrawQ(i);
1058                         highlightedAction = 1;
1059                         panel_click_distance = mousepos - panel_pos;
1060                         return;
1061                 }
1062                 // resize from topleft border
1063                 else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
1064                 {
1065                         highlightedPanel = hud_panels_from(i);
1066                         HUD_Panel_FirstInDrawQ(i);
1067                         highlightedAction = 2;
1068                         resizeCorner = 1;
1069                         panel_click_distance = mousepos - panel_pos;
1070                         panel_click_resizeorigin = panel_pos + panel_size;
1071                         return;
1072                 }
1073                 // resize from topright border
1074                 else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y - border && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + 0.5 * panel_size.y)
1075                 {
1076                         highlightedPanel = hud_panels_from(i);
1077                         HUD_Panel_FirstInDrawQ(i);
1078                         highlightedAction = 2;
1079                         resizeCorner = 2;
1080                         panel_click_distance.x = panel_size.x - mousepos.x + panel_pos.x;
1081                         panel_click_distance.y = mousepos.y - panel_pos.y;
1082                         panel_click_resizeorigin = panel_pos + eY * panel_size.y;
1083                         return;
1084                 }
1085                 // resize from bottomleft border
1086                 else if(mousepos.x >= panel_pos.x - border && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + 0.5 * panel_size.x && mousepos.y <= panel_pos.y + panel_size.y + border)
1087                 {
1088                         highlightedPanel = hud_panels_from(i);
1089                         HUD_Panel_FirstInDrawQ(i);
1090                         highlightedAction = 2;
1091                         resizeCorner = 3;
1092                         panel_click_distance.x = mousepos.x - panel_pos.x;
1093                         panel_click_distance.y = panel_size.y - mousepos.y + panel_pos.y;
1094                         panel_click_resizeorigin = panel_pos + eX * panel_size.x;
1095                         return;
1096                 }
1097                 // resize from bottomright border
1098                 else if(mousepos.x >= panel_pos.x + 0.5 * panel_size.x && mousepos.y >= panel_pos.y + 0.5 * panel_size.y && mousepos.x <= panel_pos.x + panel_size.x + border && mousepos.y <= panel_pos.y + panel_size.y + border)
1099                 {
1100                         highlightedPanel = hud_panels_from(i);
1101                         HUD_Panel_FirstInDrawQ(i);
1102                         highlightedAction = 2;
1103                         resizeCorner = 4;
1104                         panel_click_distance = panel_size - mousepos + panel_pos;
1105                         panel_click_resizeorigin = panel_pos;
1106                         return;
1107                 }
1108         }
1109         highlightedPanel = NULL;
1110         highlightedAction = 0;
1111 }
1112
1113 void HUD_Panel_EnableMenu()
1114 {
1115         hud_configure_menu_open = 2;
1116         localcmd("menu_showhudoptions ", highlightedPanel.panel_name, "\n");
1117 }
1118 void HUD_Panel_Mouse()
1119 {
1120         if(autocvar__menu_alpha == 1)
1121                 return;
1122
1123         if(mouseClicked)
1124         {
1125                 if(prevMouseClicked == 0)
1126                 {
1127                         if (tab_panel)
1128                         {
1129                                 //stop ctrl-tab selection
1130                                 tab_panel = NULL;
1131                                 reset_tab_panels();
1132                         }
1133                         HUD_Panel_Highlight(mouseClicked & S_MOUSE1); // sets highlightedPanel, highlightedAction, panel_click_distance, panel_click_resizeorigin
1134                                                                         // and calls HUD_Panel_UpdatePosSize() for the highlighted panel
1135                         if (highlightedPanel)
1136                         {
1137                                 highlightedPanel_initial_pos = panel_pos;
1138                                 highlightedPanel_initial_size = panel_size;
1139                         }
1140                         // doubleclick check
1141                         if ((mouseClicked & S_MOUSE1) && time - prevMouseClickedTime < 0.4 && highlightedPanel && prevMouseClickedPos == mousepos)
1142                         {
1143                                 mouseClicked = 0; // to prevent spam, I guess.
1144                                 HUD_Panel_EnableMenu();
1145                         }
1146                         else
1147                         {
1148                                 if (mouseClicked & S_MOUSE1)
1149                                 {
1150                                         prevMouseClickedTime = time;
1151                                         prevMouseClickedPos = mousepos;
1152                                 }
1153                                 cursor_type = HUD_Panel_Check_Mouse_Pos(mouseClicked & S_MOUSE1);
1154                         }
1155                 }
1156                 else
1157                 {
1158                         panel = highlightedPanel;
1159                         HUD_Panel_UpdatePosSize();
1160                 }
1161
1162                 if (highlightedPanel)
1163                 {
1164                         drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
1165                         if (highlightedPanel_initial_pos != panel_pos || highlightedPanel_initial_size != panel_size)
1166                         {
1167                                 hud_configure_checkcollisions = (!(hudShiftState & S_CTRL) && autocvar_hud_configure_checkcollisions);
1168                                 // backup!
1169                                 panel_pos_backup = highlightedPanel_initial_pos;
1170                                 panel_size_backup = highlightedPanel_initial_size;
1171                                 highlightedPanel_backup = highlightedPanel;
1172                         }
1173                         else
1174                                 // in case the clicked panel is inside another panel and we aren't
1175                                 // moving it, avoid the immediate "fix" of its position/size
1176                                 // (often unwanted and hateful) by disabling collisions check
1177                                 hud_configure_checkcollisions = false;
1178                 }
1179
1180                 if(highlightedAction == 1)
1181                         HUD_Panel_SetPos(mousepos - panel_click_distance);
1182                 else if(highlightedAction == 2)
1183                 {
1184                         vector mySize = '0 0 0';
1185                         if(resizeCorner == 1) {
1186                                 mySize.x = panel_click_resizeorigin.x - (mousepos.x - panel_click_distance.x);
1187                                 mySize.y = panel_click_resizeorigin.y - (mousepos.y - panel_click_distance.y);
1188                         } else if(resizeCorner == 2) {
1189                                 mySize.x = mousepos.x + panel_click_distance.x - panel_click_resizeorigin.x;
1190                                 mySize.y = panel_click_distance.y + panel_click_resizeorigin.y - mousepos.y;
1191                         } else if(resizeCorner == 3) {
1192                                 mySize.x = panel_click_resizeorigin.x + panel_click_distance.x - mousepos.x;
1193                                 mySize.y = mousepos.y + panel_click_distance.y - panel_click_resizeorigin.y;
1194                         } else { // resizeCorner == 4
1195                                 mySize.x = mousepos.x - (panel_click_resizeorigin.x - panel_click_distance.x);
1196                                 mySize.y = mousepos.y - (panel_click_resizeorigin.y - panel_click_distance.y);
1197                         }
1198                         HUD_Panel_SetPosSize(mySize);
1199                 }
1200         }
1201         else
1202         {
1203                 if(prevMouseClicked)
1204                         highlightedAction = 0;
1205                 if(hud_configure_menu_open == 2)
1206                         cursor_type = CURSOR_NORMAL;
1207                 else
1208                         cursor_type = HUD_Panel_Check_Mouse_Pos(true);
1209                 if (cursor_type != CURSOR_NORMAL && !tab_panel) // mouse over a panel?
1210                         drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .1, DRAWFLAG_NORMAL);
1211         }
1212 }
1213 void HUD_Configure_DrawGrid()
1214 {
1215         float i;
1216         if(autocvar_hud_configure_grid && autocvar_hud_configure_grid_alpha)
1217         {
1218                 hud_configure_gridSize.x = bound(0.005, cvar("hud_configure_grid_xsize"), 0.2);
1219                 hud_configure_gridSize.y = bound(0.005, cvar("hud_configure_grid_ysize"), 0.2);
1220                 hud_configure_realGridSize.x = hud_configure_gridSize.x * vid_conwidth;
1221                 hud_configure_realGridSize.y = hud_configure_gridSize.y * vid_conheight;
1222                 vector s;
1223                 // x-axis
1224                 s = vec2(1, vid_conheight);
1225                 for(i = 1; i < 1/hud_configure_gridSize.x; ++i)
1226                         drawfill(eX * i * hud_configure_realGridSize.x, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
1227                 // y-axis
1228                 s = vec2(vid_conwidth, 1);
1229                 for(i = 1; i < 1/hud_configure_gridSize.y; ++i)
1230                         drawfill(eY * i * hud_configure_realGridSize.y, s, '0.5 0.5 0.5', autocvar_hud_configure_grid_alpha, DRAWFLAG_NORMAL);
1231         }
1232 }
1233
1234 float _menu_alpha_prev;
1235 void HUD_Configure_Frame()
1236 {
1237         int i;
1238         if(autocvar__hud_configure)
1239         {
1240                 if(isdemo() || intermission == 2 || scoreboard_active)
1241                 {
1242                         HUD_Configure_Exit_Force();
1243                         return;
1244                 }
1245
1246                 if(!hud_configure_prev)
1247                 {
1248                         hudShiftState = 0;
1249                         for(i = hud_panels_COUNT - 1; i >= 0; --i)
1250                                 hud_panels_from(panel_order[i]).update_time = time;
1251                 }
1252
1253                 // NOTE this check is necessary because _menu_alpha isn't updated the frame the menu gets enabled
1254                 if(autocvar__menu_alpha != _menu_alpha_prev)
1255                 {
1256                         if(autocvar__menu_alpha == 0)
1257                                 hud_configure_menu_open = 0;
1258                         _menu_alpha_prev = autocvar__menu_alpha;
1259                 }
1260
1261                 HUD_Configure_DrawGrid();
1262         }
1263         else if(hud_configure_prev)
1264         {
1265                 if(hud_configure_menu_open)
1266                         hud_configure_menu_open = 0;
1267                 hud_dynamic_shake_factor = -1;
1268         }
1269 }
1270
1271 const float hlBorderSize = 2;
1272 const string hlBorder = "gfx/hud/default/border_highlighted";
1273 const string hlBorder2 = "gfx/hud/default/border_highlighted2";
1274 void HUD_Panel_HlBorder(float myBorder, vector color, float theAlpha)
1275 {
1276         vector pos = panel_pos - vec2(myBorder, myBorder);
1277         drawfill(pos, panel_size + '2 2 0' * myBorder, '0 0.5 1', .5 * theAlpha, DRAWFLAG_NORMAL);
1278         drawpic_tiled(pos, hlBorder, '8 1 0' * hlBorderSize, vec2(panel_size.x + 2 * myBorder, hlBorderSize), color, theAlpha, DRAWFLAG_NORMAL);
1279         drawpic_tiled(pos + eY * (panel_size.y + 2 * myBorder - hlBorderSize), hlBorder, '8 1 0' * hlBorderSize, vec2(panel_size.x + 2 * myBorder, hlBorderSize), color, theAlpha, DRAWFLAG_NORMAL);
1280         pos.y += hlBorderSize;
1281         drawpic_tiled(pos, hlBorder2, '1 8 0' * hlBorderSize, vec2(hlBorderSize, panel_size.y + 2 * myBorder - 2 * hlBorderSize), color, theAlpha, DRAWFLAG_NORMAL);
1282         drawpic_tiled(pos + eX * (panel_size.x + 2 * myBorder - hlBorderSize), hlBorder2, '1 8 0' * hlBorderSize, vec2(hlBorderSize, panel_size.y + 2 * myBorder - 2 * hlBorderSize), color, theAlpha, DRAWFLAG_NORMAL);
1283 }
1284
1285 void HUD_Configure_PostDraw()
1286 {
1287         if(autocvar__hud_configure)
1288         {
1289                 if(tab_panel)
1290                 {
1291                         panel = tab_panel;
1292                         HUD_Panel_UpdatePosSize();
1293                         drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', .2, DRAWFLAG_NORMAL);
1294                 }
1295                 if(highlightedPanel)
1296                 {
1297                         panel = highlightedPanel;
1298                         HUD_Panel_UpdatePosSize();
1299                         HUD_Panel_HlBorder(panel_bg_border * hlBorderSize, '0 0.5 1', 0.4 * (1 - autocvar__menu_alpha));
1300                 }
1301         }
1302 }