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