Xonotic QuakeC
The free, fast arena FPS with crisp movement and a wide array of weapons
hud_config.qc
Go to the documentation of this file.
1#include "hud_config.qh"
2
3#include <client/draw.qh>
4#include <client/hud/hud.qh>
7#include <client/view.qh>
8
9// Save the config
10void HUD_Panel_ExportCfg(string cfgname)
11{
12 string filename = strcat("hud_", autocvar_hud_skin, "_", cfgname, ".cfg");
13 float fh = fopen(filename, FILE_WRITE);
14 if (fh >= 0)
15 {
16 HUD_Write("//title \n");
17 HUD_Write("//author \n");
18 HUD_Write("\n");
19 HUD_Write_Cvar("hud_skin");
20 HUD_Write_Cvar("hud_panel_bg");
21 HUD_Write_Cvar("hud_panel_bg_color");
22 HUD_Write_Cvar("hud_panel_bg_color_team");
23 HUD_Write_Cvar("hud_panel_bg_alpha");
24 HUD_Write_Cvar("hud_panel_bg_border");
25 HUD_Write_Cvar("hud_panel_bg_padding");
26 HUD_Write_Cvar("hud_panel_fg_alpha");
27 HUD_Write("\n");
28
29 HUD_Write_Cvar("hud_dock");
30 HUD_Write_Cvar("hud_dock_color");
31 HUD_Write_Cvar("hud_dock_color_team");
32 HUD_Write_Cvar("hud_dock_alpha");
33 HUD_Write("\n");
34
35 HUD_Write_Cvar("hud_progressbar_alpha");
36 HUD_Write_Cvar("hud_progressbar_strength_color");
37 HUD_Write_Cvar("hud_progressbar_superweapons_color");
38 HUD_Write_Cvar("hud_progressbar_shield_color");
39 HUD_Write_Cvar("hud_progressbar_health_color");
40 HUD_Write_Cvar("hud_progressbar_armor_color");
41 HUD_Write_Cvar("hud_progressbar_fuel_color");
42 HUD_Write_Cvar("hud_progressbar_oxygen_color");
43 HUD_Write_Cvar("hud_progressbar_nexball_color");
44 HUD_Write_Cvar("hud_progressbar_speed_color");
45 HUD_Write_Cvar("hud_progressbar_acceleration_color");
46 HUD_Write_Cvar("hud_progressbar_acceleration_neg_color");
47 HUD_Write_Cvar("hud_progressbar_vehicles_ammo1_color");
48 HUD_Write_Cvar("hud_progressbar_vehicles_ammo2_color");
49 HUD_Write("\n");
50
51 HUD_Write_Cvar("_hud_panelorder");
52 HUD_Write("\n");
53
54 HUD_Write_Cvar("hud_configure_grid");
55 HUD_Write_Cvar("hud_configure_grid_xsize");
56 HUD_Write_Cvar("hud_configure_grid_ysize");
57 HUD_Write("\n");
58
59 // common cvars for all panels
60 string str = "";
61 for (int i = 0; i < REGISTRY_COUNT(hud_panels); ++i)
62 {
63 panel = REGISTRY_GET(hud_panels, i);
64
65 HUD_Write_PanelCvar("_pos");
66 HUD_Write_PanelCvar("_size");
68 HUD_Write_PanelCvar("_bg_color");
69 HUD_Write_PanelCvar("_bg_color_team");
70 HUD_Write_PanelCvar("_bg_alpha");
71 HUD_Write_PanelCvar("_bg_border");
72 HUD_Write_PanelCvar("_bg_padding");
73 panel.panel_export(fh);
74 HUD_Write("\n");
75 }
76
77 HUD_Write("menu_sync\n"); // force the menu to reread the cvars, so that the dialogs are updated
78
79 LOG_INFOF(_("^2Successfully exported to %s! (Note: It's saved in data/data/)"), filename);
80 fclose(fh);
81 }
82 else
83 LOG_INFOF(_("^1Couldn't write to %s"), filename);
84}
85
87{
89 {
91 localcmd("togglemenu\n");
92 }
94 cvar_set("_hud_configure", "0");
95}
96
97// check if move will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
99{
100 vector myCenter, targCenter;
101 vector myTarget = myPos;
102 for (int i = 0; i < REGISTRY_COUNT(hud_panels); ++i)
103 {
104 panel = REGISTRY_GET(hud_panels, i);
105 if (!(panel.panel_configflags & PANEL_CONFIG_MAIN))
106 continue;
107 if (panel == highlightedPanel)
108 continue;
110 if (!panel_enabled)
111 continue;
112
113 panel_pos -= '1 1 0' * panel_bg_border;
114 panel_size += '2 2 0' * panel_bg_border;
115
116 if (myPos.y + mySize.y < panel_pos.y)
117 continue;
118 if (myPos.y > panel_pos.y + panel_size.y)
119 continue;
120
121 if (myPos.x + mySize.x < panel_pos.x)
122 continue;
123 if (myPos.x > panel_pos.x + panel_size.x)
124 continue;
125
126 // OK, there IS a collision.
127
128 myCenter.x = myPos.x + 0.5 * mySize.x;
129 myCenter.y = myPos.y + 0.5 * mySize.y;
130
131 targCenter.x = panel_pos.x + 0.5 * panel_size.x;
132 targCenter.y = panel_pos.y + 0.5 * panel_size.y;
133
134 if (myCenter.x < targCenter.x && myCenter.y < targCenter.y) // top left (of the target panel)
135 {
136 if (myPos.x + mySize.x - panel_pos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
137 myTarget.x = panel_pos.x - mySize.x;
138 else // push it upwards
139 myTarget.y = panel_pos.y - mySize.y;
140 }
141 else if (myCenter.x > targCenter.x && myCenter.y < targCenter.y) // top right
142 {
143 if (panel_pos.x + panel_size.x - myPos.x < myPos.y + mySize.y - panel_pos.y) // push it to the side
144 myTarget.x = panel_pos.x + panel_size.x;
145 else // push it upwards
146 myTarget.y = panel_pos.y - mySize.y;
147 }
148 else if (myCenter.x < targCenter.x && myCenter.y > targCenter.y) // bottom left
149 {
150 if (myPos.x + mySize.x - panel_pos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
151 myTarget.x = panel_pos.x - mySize.x;
152 else // push it downwards
153 myTarget.y = panel_pos.y + panel_size.y;
154 }
155 else if (myCenter.x > targCenter.x && myCenter.y > targCenter.y) // bottom right
156 {
157 if (panel_pos.x + panel_size.x - myPos.x < panel_pos.y + panel_size.y - myPos.y) // push it to the side
158 myTarget.x = panel_pos.x + panel_size.x;
159 else // push it downwards
160 myTarget.y = panel_pos.y + panel_size.y;
161 }
162 //if (cvar("hud_configure_checkcollisions_debug"))
163 //drawfill(panel_pos, panel_size, '1 1 0', 0.3, DRAWFLAG_NORMAL);
164 }
165
166 return myTarget;
167}
168
170{
173 vector mySize = panel_size;
174
175 //if (cvar("hud_configure_checkcollisions_debug"))
176 //drawfill(pos, mySize, '1 1 1', 0.2, DRAWFLAG_NORMAL);
177
179 {
182 }
183
185 pos = HUD_Panel_CheckMove(pos, mySize);
186
187 pos.x = bound(0, pos.x, vid_conwidth - mySize.x);
188 pos.y = bound(0, pos.y, vid_conheight - mySize.y);
189
190 string s = strcat(ftos_mindecimals(pos.x / vid_conwidth), " ", ftos_mindecimals(pos.y / vid_conheight));
191 cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
192}
193
194// check if resize will result in panel being moved into another panel. If so, return snapped vector, otherwise return the given vector
196{
197 vector targEndPos;
198 vector dist;
199 float ratio = mySize.x / mySize.y;
200 for (int i = 0; i < REGISTRY_COUNT(hud_panels); ++i)
201 {
202 panel = REGISTRY_GET(hud_panels, i);
203 if (!(panel.panel_configflags & PANEL_CONFIG_MAIN))
204 continue;
205 if (panel == highlightedPanel)
206 continue;
208 if (!panel_enabled)
209 continue;
210
211 panel_pos -= '1 1 0' * panel_bg_border;
212 panel_size += '2 2 0' * panel_bg_border;
213
214 targEndPos = panel_pos + panel_size;
215
216 // resizeorigin is WITHIN target panel, just abort any collision testing against that particular panel to produce expected behaviour!
217 if (resizeorigin.x > panel_pos.x && resizeorigin.x < targEndPos.x && resizeorigin.y > panel_pos.y && resizeorigin.y < targEndPos.y)
218 continue;
219
220 if (resizeCorner == 1)
221 {
222 // check if this panel is on our way
223 if (resizeorigin.x <= panel_pos.x)
224 continue;
225 if (resizeorigin.y <= panel_pos.y)
226 continue;
227 if (targEndPos.x <= resizeorigin.x - mySize.x)
228 continue;
229 if (targEndPos.y <= resizeorigin.y - mySize.y)
230 continue;
231
232 // there is a collision:
233 // detect which side of the panel we are facing is actually limiting the resizing
234 // (which side the resize direction finds for first) and reduce the size up to there
235 //
236 // dist is the distance between resizeorigin and the "analogous" point of the panel
237 // in this case between resizeorigin (bottom-right point) and the bottom-right point of the panel
238 dist.x = resizeorigin.x - targEndPos.x;
239 dist.y = resizeorigin.y - targEndPos.y;
240 if (dist.y <= 0 || dist.x / dist.y > ratio)
241 mySize.x = min(mySize.x, dist.x);
242 else
243 mySize.y = min(mySize.y, dist.y);
244 }
245 else if (resizeCorner == 2)
246 {
247 if (resizeorigin.x >= targEndPos.x)
248 continue;
249 if (resizeorigin.y <= panel_pos.y)
250 continue;
251 if (panel_pos.x >= resizeorigin.x + mySize.x)
252 continue;
253 if (targEndPos.y <= resizeorigin.y - mySize.y)
254 continue;
255
256 dist.x = panel_pos.x - resizeorigin.x;
257 dist.y = resizeorigin.y - targEndPos.y;
258 if (dist.y <= 0 || dist.x / dist.y > ratio)
259 mySize.x = min(mySize.x, dist.x);
260 else
261 mySize.y = min(mySize.y, dist.y);
262 }
263 else if (resizeCorner == 3)
264 {
265 if (resizeorigin.x <= panel_pos.x)
266 continue;
267 if (resizeorigin.y >= targEndPos.y)
268 continue;
269 if (targEndPos.x <= resizeorigin.x - mySize.x)
270 continue;
271 if (panel_pos.y >= resizeorigin.y + mySize.y)
272 continue;
273
274 dist.x = resizeorigin.x - targEndPos.x;
275 dist.y = panel_pos.y - resizeorigin.y;
276 if (dist.y <= 0 || dist.x / dist.y > ratio)
277 mySize.x = min(mySize.x, dist.x);
278 else
279 mySize.y = min(mySize.y, dist.y);
280 }
281 else if (resizeCorner == 4)
282 {
283 if (resizeorigin.x >= targEndPos.x)
284 continue;
285 if (resizeorigin.y >= targEndPos.y)
286 continue;
287 if (panel_pos.x >= resizeorigin.x + mySize.x)
288 continue;
289 if (panel_pos.y >= resizeorigin.y + mySize.y)
290 continue;
291
292 dist.x = panel_pos.x - resizeorigin.x;
293 dist.y = panel_pos.y - resizeorigin.y;
294 if (dist.y <= 0 || dist.x / dist.y > ratio)
295 mySize.x = min(mySize.x, dist.x);
296 else
297 mySize.y = min(mySize.y, dist.y);
298 }
299 //if (cvar("hud_configure_checkcollisions_debug"))
300 //drawfill(panel_pos, panel_size, '1 1 0', 0.3, DRAWFLAG_NORMAL);
301 }
302
303 return mySize;
304}
305
307{
310 vector resizeorigin = panel_click_resizeorigin;
311 vector myPos;
312
313 // minimum panel size cap
314 mySize.x = max(0.025 * vid_conwidth, mySize.x);
315 mySize.y = max(0.025 * vid_conheight, mySize.y);
316
317 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.
318 {
319 mySize.x = max(17 * autocvar_con_chatsize, mySize.x);
320 mySize.y = max(2 * autocvar_con_chatsize + 2 * panel_bg_padding, mySize.y);
321 }
322
323 // collision testing|
324 // -----------------+
325
326 // we need to know pos at this stage, but it might still change later if we hit a screen edge/other panel (?)
327 if (resizeCorner == 1)
328 {
329 myPos.x = resizeorigin.x - mySize.x;
330 myPos.y = resizeorigin.y - mySize.y;
331 }
332 else if (resizeCorner == 2)
333 {
334 myPos.x = resizeorigin.x;
335 myPos.y = resizeorigin.y - mySize.y;
336 }
337 else if (resizeCorner == 3)
338 {
339 myPos.x = resizeorigin.x - mySize.x;
340 myPos.y = resizeorigin.y;
341 }
342 else // resizeCorner == 4
343 {
344 myPos.x = resizeorigin.x;
345 myPos.y = resizeorigin.y;
346 }
347
348 // left/top screen edges
349 if (myPos.x < 0)
350 mySize.x = mySize.x + myPos.x;
351 if (myPos.y < 0)
352 mySize.y = mySize.y + myPos.y;
353
354 // bottom/right screen edges
355 if (myPos.x + mySize.x > vid_conwidth)
356 mySize.x = vid_conwidth - myPos.x;
357 if (myPos.y + mySize.y > vid_conheight)
358 mySize.y = vid_conheight - myPos.y;
359
360 //if (cvar("hud_configure_checkcollisions_debug"))
361 //drawfill(myPos, mySize, '1 1 1', 0.2, DRAWFLAG_NORMAL);
362
363 // before checkresize, otherwise panel can be snapped partially inside another panel or panel aspect ratio can be broken
365 {
366 mySize.x = floor((mySize.x / vid_conwidth) / hud_configure_gridSize.x + 0.5) * hud_configure_realGridSize.x;
367 mySize.y = floor((mySize.y / vid_conheight) / hud_configure_gridSize.y + 0.5) * hud_configure_realGridSize.y;
368 }
369
371 mySize = HUD_Panel_CheckResize(mySize, resizeorigin);
372
373 // 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)
374 mySize.x = max(0.025 * vid_conwidth, mySize.x);
375 mySize.y = max(0.025 * vid_conheight, mySize.y);
376
377 // do another pos check, as size might have changed by now
378 if (resizeCorner == 1)
379 {
380 myPos.x = resizeorigin.x - mySize.x;
381 myPos.y = resizeorigin.y - mySize.y;
382 }
383 else if (resizeCorner == 2)
384 {
385 myPos.x = resizeorigin.x;
386 myPos.y = resizeorigin.y - mySize.y;
387 }
388 else if (resizeCorner == 3)
389 {
390 myPos.x = resizeorigin.x - mySize.x;
391 myPos.y = resizeorigin.y;
392 }
393 else // resizeCorner == 4
394 {
395 myPos.x = resizeorigin.x;
396 myPos.y = resizeorigin.y;
397 }
398
399 //if (cvar("hud_configure_checkcollisions_debug"))
400 //drawfill(myPos, mySize, '0 1 0', 0.3, DRAWFLAG_NORMAL);
401
402 string s = strcat(ftos_mindecimals(mySize.x / vid_conwidth), " ", ftos_mindecimals(mySize.y / vid_conheight));
403 cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
404
405 s = strcat(ftos_mindecimals(myPos.x / vid_conwidth), " ", ftos_mindecimals(myPos.y / vid_conheight));
406 cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_pos"), s);
407}
408
411void HUD_Panel_Arrow_Action(float nPrimary)
412{
413 if (!highlightedPanel)
414 return;
415
417
418 float step;
420 {
421 if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
422 {
425 else
426 step = 2 * hud_configure_realGridSize.y;
427 }
428 else
429 {
432 else
433 step = 2 * hud_configure_realGridSize.x;
434 }
435 }
436 else
437 {
438 if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW)
439 step = vid_conheight;
440 else
441 step = vid_conwidth;
443 step = (step / 256); // more precision
444 else
445 step = (step / 64) * (1 + 2 * (time - pressed_key_time));
446 }
447
450
453
454 if (hudShiftState & S_ALT) // resize
455 {
456 if (nPrimary == K_UPARROW)
457 resizeCorner = 1;
458 else if (nPrimary == K_RIGHTARROW)
459 resizeCorner = 2;
460 else if (nPrimary == K_LEFTARROW)
461 resizeCorner = 3;
462 else // if (nPrimary == K_DOWNARROW)
463 resizeCorner = 4;
464
465 // ctrl+arrow reduces the size, instead of increasing it
466 // Note that ctrl disables collisions check too, but it's fine
467 // since we don't collide with anything reducing the size
468 if (hudShiftState & S_CTRL)
469 {
470 step = -step;
472 }
473
474 vector mySize = panel_size;
476 if (resizeCorner == 1)
477 {
478 panel_click_resizeorigin += mySize;
479 mySize.y += step;
480 }
481 else if (resizeCorner == 2)
482 {
483 panel_click_resizeorigin.y += mySize.y;
484 mySize.x += step;
485 }
486 else if (resizeCorner == 3)
487 {
488 panel_click_resizeorigin.x += mySize.x;
489 mySize.x += step;
490 }
491 else // resizeCorner == 4
492 mySize.y += step;
493 HUD_Panel_SetPosSize(mySize);
494 }
495 else // move
496 {
497 vector pos = panel_pos;
498 if (nPrimary == K_UPARROW)
499 pos.y -= step;
500 else if (nPrimary == K_DOWNARROW)
501 pos.y += step;
502 else if (nPrimary == K_LEFTARROW)
503 pos.x -= step;
504 else // if (nPrimary == K_RIGHTARROW)
505 pos.x += step;
506
507 HUD_Panel_SetPos(pos);
508 }
509
512
514 {
515 // backup!
520 }
521}
522
528{
529 for (int i = 0; i < REGISTRY_COUNT(hud_panels); ++i)
530 tab_panels[i] = NULL;
531}
532float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
533{
535 return false;
536
537 if (bInputType == 3)
538 {
539 mousepos.x = nPrimary;
540 mousepos.y = nSecondary;
541 return true;
542 }
543
544 if (bInputType == 2)
545 return false;
546
547 // at this point bInputType can only be 0 or 1 (key pressed or released)
548 bool key_pressed = bInputType == 0;
549
550 // block any input while a menu dialog is fading
551 // don't block mousepos read as it leads to cursor jumps in the interaction with the menu
553 {
554 hudShiftState = 0;
555 mouseClicked = 0;
556 return true;
557 }
558
559 int hudShiftState_prev = hudShiftState;
560 int mouseClicked_prev = mouseClicked;
561 if (key_pressed)
562 {
563 if (nPrimary == K_ALT) hudShiftState |= S_ALT;
564 if (nPrimary == K_CTRL) hudShiftState |= S_CTRL;
565 if (nPrimary == K_SHIFT) hudShiftState |= S_SHIFT;
566 if (nPrimary == K_MOUSE1) mouseClicked |= S_MOUSE1;
567 if (nPrimary == K_MOUSE2) mouseClicked |= S_MOUSE2;
568 }
569 else
570 {
571 if (nPrimary == K_ALT) hudShiftState &= ~S_ALT;
572 if (nPrimary == K_CTRL) hudShiftState &= ~S_CTRL;
573 if (nPrimary == K_SHIFT) hudShiftState &= ~S_SHIFT;
574 if (nPrimary == K_MOUSE1) mouseClicked &= ~S_MOUSE1;
575 if (nPrimary == K_MOUSE2) mouseClicked &= ~S_MOUSE2;
576 }
577
578 if (nPrimary == K_CTRL)
579 {
580 if (!key_pressed) // ctrl has been released
581 {
582 if (tab_panel)
583 {
584 // switch to selected panel
588 }
589 tab_panel = NULL;
591 }
592 }
593
594 string s;
595 if (nPrimary == K_ESCAPE)
596 {
597 if (!key_pressed)
598 return true;
600 localcmd("menu_showhudexit\n");
601 }
602 else if (nPrimary == K_BACKSPACE && hudShiftState & S_CTRL)
603 {
604 if (!key_pressed)
605 return true;
608 }
609 else if (nPrimary == K_TAB && hudShiftState & S_CTRL) // switch panel
610 {
611 if (!key_pressed || mouseClicked)
612 return true;
613
614 // FIXME minor bug: if a panel is highlighted, has the same pos_x and
615 // lays in the same level of another panel then the next consecutive
616 // CTRL TAB presses will reselect once more the highlighted panel
617
618 entity starting_panel;
619 entity old_tab_panel = tab_panel;
620 if (!tab_panel) // first press of TAB
621 {
623 {
626 }
627 else
628 panel_pos = '0 0 0';
629 starting_panel = highlightedPanel;
630 tab_panel_pos = panel_pos; // to compute level
631 }
632 else
633 {
634 if ((!tab_backward && (hudShiftState & S_SHIFT)) || (tab_backward && !(hudShiftState & S_SHIFT))) // tab direction changed?
636 starting_panel = tab_panel;
637 }
639
640 float k, level = 0, start_posX;
641 vector candidate_pos = '0 0 0';
642 const float LEVELS_NUM = 4;
643 float level_height = vid_conheight / LEVELS_NUM;
644 LABEL(find_tab_panel)
645 level = floor(tab_panel_pos.y / level_height) * level_height; // starting level
646 candidate_pos.x = !tab_backward ? vid_conwidth : 0;
647 start_posX = tab_panel_pos.x;
648 tab_panel = NULL;
649 k = 0;
650 while (++k)
651 {
652 for (int i = 0; i < REGISTRY_COUNT(hud_panels); ++i)
653 {
654 panel = REGISTRY_GET(hud_panels, i);
655 if (!(panel.panel_configflags & PANEL_CONFIG_MAIN))
656 continue;
657 if (panel == tab_panels[i] || panel == starting_panel)
658 continue;
660 if (panel_pos.y >= level && (panel_pos.y - level) < level_height)
661 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)))
662 || (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))))
663 {
665 tab_panel_pos = candidate_pos = panel_pos;
666 }
667 }
668 if (tab_panel)
669 break;
670 if (k == LEVELS_NUM) // tab_panel not found
671 {
673 if (!old_tab_panel)
674 {
675 tab_panel = NULL;
676 return true;
677 }
678 starting_panel = old_tab_panel;
679 old_tab_panel = NULL;
680 goto find_tab_panel; // u must find tab_panel!
681 }
682 if (!tab_backward)
683 {
684 level = (level + level_height) % vid_conheight;
685 start_posX = 0;
686 candidate_pos.x = vid_conwidth;
687 }
688 else
689 {
690 level = (level - level_height) % vid_conheight;
691 start_posX = vid_conwidth;
692 candidate_pos.x = 0;
693 }
694 }
695
696 tab_panels[tab_panel.panel_id] = tab_panel;
697 }
698 else if (nPrimary == K_SPACE && hudShiftState & S_CTRL) // enable/disable highlighted panel or dock
699 {
700 if (!key_pressed || mouseClicked)
701 return true;
702
704 {
705 if (panel.panel_configflags & PANEL_CONFIG_CANBEOFF)
706 cvar_set(strcat("hud_panel_", highlightedPanel.panel_name), ftos(!cvar(strcat("hud_panel_", highlightedPanel.panel_name))));
707 }
708 else
709 cvar_set(strcat("hud_dock"), (autocvar_hud_dock == "") ? "dock" : "");
710 }
711 else if (nPrimary == 'c' && hudShiftState & S_CTRL) // copy highlighted panel size
712 {
713 if (!key_pressed || mouseClicked)
714 return true;
715
717 {
721 }
722 }
723 else if (nPrimary == 'v' && hudShiftState & S_CTRL) // past copied size on the highlighted panel
724 {
725 if (!key_pressed || mouseClicked)
726 return true;
727
728 if (panel_size_copied == '0 0 0' || !highlightedPanel)
729 return true;
730
733
734 // reduce size if it'd go beyond screen boundaries
735 vector tmp_size = panel_size_copied;
737 tmp_size.x = vid_conwidth - panel_pos.x;
739 tmp_size.y = vid_conheight - panel_pos.y;
740
741 if (panel_size == tmp_size)
742 return true;
743
744 // backup first!
748
749 s = strcat(ftos_mindecimals(tmp_size.x/vid_conwidth), " ", ftos_mindecimals(tmp_size.y/vid_conheight));
750 cvar_set(strcat("hud_panel_", highlightedPanel.panel_name, "_size"), s);
751 }
752 else if (nPrimary == 'z' && hudShiftState & S_CTRL) // undo last action
753 {
754 if (!key_pressed || mouseClicked)
755 return true;
756 // restore previous values
758 {
760 cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_pos"), s);
762 cvar_set(strcat("hud_panel_", highlightedPanel_backup.panel_name, "_size"), s);
764 }
765 }
766 else if (nPrimary == 's' && hudShiftState & S_CTRL) // save config
767 {
768 if (!key_pressed || mouseClicked)
769 return true;
770 localcmd("hud save myconfig\n");
771 }
772 else if (nPrimary == K_UPARROW || nPrimary == K_DOWNARROW || nPrimary == K_LEFTARROW || nPrimary == K_RIGHTARROW)
773 {
774 if (!key_pressed)
775 {
777 return true;
778 }
779 else if (pressed_key_time == 0)
781
782 if (!mouseClicked)
783 HUD_Panel_Arrow_Action(nPrimary); // move or resize panel
784 }
785 else if (nPrimary == K_ENTER || nPrimary == K_SPACE || nPrimary == K_KP_ENTER)
786 {
787 if (bInputType == 1)
788 return true;
791 }
792 else if (nPrimary == K_PAUSE)
793 return false;
794 else if (hudShiftState_prev == hudShiftState && mouseClicked_prev == mouseClicked)
795 {
796 // allow console bind to work
797 string con_keys = findkeysforcommand("toggleconsole", 0);
798 int keys = tokenize(con_keys); // findkeysforcommand returns data for this
799 for (int i = 0; i < keys; ++i)
800 if (nPrimary == stof(argv(i)))
801 return false; // hit console bind
802 }
803
804 return true;
805}
806
807int HUD_Panel_Check_Mouse_Pos(bool allow_move)
808{
809 int i, j = 0;
810 while (j < REGISTRY_COUNT(hud_panels))
811 {
812 i = panel_order[j];
813 ++j;
814
815 panel = REGISTRY_GET(hud_panels, i);
816 if (!(panel.panel_configflags & PANEL_CONFIG_MAIN))
817 continue;
819
820 float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
821
822 // move
823 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)
824 return CURSOR_MOVE;
825 // resize from topleft border
826 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)
827 return CURSOR_RESIZE;
828 // resize from topright border
829 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)
830 return CURSOR_RESIZE2;
831 // resize from bottomleft border
832 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)
833 return CURSOR_RESIZE2;
834 // resize from bottomright border
835 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)
836 return CURSOR_RESIZE;
837 }
838 return CURSOR_NORMAL;
839}
840
841// move a panel to the beginning of the panel order array (which means it gets drawn last, on top of everything else)
843{
844 int i, place = -1;
845 // find out where in the array our current id is, save into place
846 for (i = 0; i < REGISTRY_COUNT(hud_panels); ++i)
847 if (panel_order[i] == id)
848 {
849 place = i;
850 break;
851 }
852
853 // place last if we didn't find a place for it yet (probably new panel, or screwed up cvar)
854 if (place == -1)
855 place = REGISTRY_COUNT(hud_panels) - 1;
856
857 // move all ids up by one step in the array until "place"
858 for (i = place; i > 0; --i)
859 panel_order[i] = panel_order[i - 1];
860 // now save the new top id
861 panel_order[0] = id;
862
863 // let's save them into the cvar by some strcat trickery
864 string s = "";
865 for (i = 0; i < REGISTRY_COUNT(hud_panels); ++i)
866 s = strcat(s, ftos(panel_order[i]), " ");
867
868 cvar_set("_hud_panelorder", s);
869 strcpy(hud_panelorder_prev, autocvar__hud_panelorder); // prevent HUD_Main from doing useless update, we already updated here
870}
871
872void HUD_Panel_Highlight(float allow_move)
873{
874 int i, j = 0;
875 while (j < REGISTRY_COUNT(hud_panels))
876 {
877 i = panel_order[j];
878 ++j;
879
880 panel = REGISTRY_GET(hud_panels, i);
881 if (!(panel.panel_configflags & PANEL_CONFIG_MAIN))
882 continue;
884
885 float border = max(8, panel_bg_border); // FORCED border so a small border size doesn't mean you can't resize
886
887 // move
888 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)
889 {
890 highlightedPanel = REGISTRY_GET(hud_panels, i);
894 return;
895 }
896 // resize from topleft border
897 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)
898 {
899 highlightedPanel = REGISTRY_GET(hud_panels, i);
902 resizeCorner = 1;
905 return;
906 }
907 // resize from topright border
908 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)
909 {
910 highlightedPanel = REGISTRY_GET(hud_panels, i);
913 resizeCorner = 2;
917 return;
918 }
919 // resize from bottomleft border
920 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)
921 {
922 highlightedPanel = REGISTRY_GET(hud_panels, i);
925 resizeCorner = 3;
929 return;
930 }
931 // resize from bottomright border
932 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)
933 {
934 highlightedPanel = REGISTRY_GET(hud_panels, i);
937 resizeCorner = 4;
940 return;
941 }
942 }
945}
946
948{
950 localcmd("menu_showhudoptions ", highlightedPanel.panel_name, "\n");
951}
952
954{
955 if (autocvar__menu_alpha == 1)
956 return;
957
958 if (mouseClicked)
959 {
960 if (prevMouseClicked == 0)
961 {
962 if (tab_panel)
963 {
964 // stop ctrl-tab selection
965 tab_panel = NULL;
967 }
968 HUD_Panel_Highlight(mouseClicked & S_MOUSE1); // sets highlightedPanel, highlightedAction, panel_click_distance, panel_click_resizeorigin
969 // and calls HUD_Panel_UpdatePosSize() for the highlighted panel
971 {
974 }
975 // doubleclick check
977 {
978 mouseClicked = 0; // to prevent spam, I guess.
980 }
981 else
982 {
984 {
987 }
989 }
990 }
991 else
992 {
995 }
996
998 {
999 drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', 0.1, DRAWFLAG_NORMAL);
1001 {
1003 // backup!
1007 }
1008 else
1009 // in case the clicked panel is inside another panel and we aren't
1010 // moving it, avoid the immediate "fix" of its position/size
1011 // (often unwanted and hateful) by disabling collisions check
1013
1014 if (time - prevMouseClickedTime > 0.25) // avoid showing the center line immediately on mouse click
1016 }
1017
1018 if (highlightedAction == 1)
1020 else if (highlightedAction == 2)
1021 {
1022 vector mySize = '0 0 0';
1023 if (resizeCorner == 1)
1024 {
1027 }
1028 else if (resizeCorner == 2)
1029 {
1032 }
1033 else if (resizeCorner == 3)
1034 {
1037 }
1038 else // resizeCorner == 4
1039 {
1042 }
1043 HUD_Panel_SetPosSize(mySize);
1044 }
1045 }
1046 else
1047 {
1048 if (prevMouseClicked)
1050 if (hud_configure_menu_open == 2)
1052 else
1054 if (cursor_type != CURSOR_NORMAL && !tab_panel) // mouse over a panel?
1055 drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', 0.1, DRAWFLAG_NORMAL);
1056 }
1057}
1059{
1061 {
1062 hud_configure_gridSize.x = bound(0.005, cvar("hud_configure_grid_xsize"), 0.2);
1063 hud_configure_gridSize.y = bound(0.005, cvar("hud_configure_grid_ysize"), 0.2);
1066 vector s;
1067 // vertical center line, wider than vertical grid lines so that it's more visible
1068 // NOTE: depending on grid size the vertical center line may not overlap any vertical grid line
1070 for (i = 0; i < n; ++i)
1071 {
1072 float xpos_rel = stof(argv(i));
1074 }
1075 // x-axis
1076 s = vec2(1, vid_conheight);
1077 for (i = 1; i < 1 / hud_configure_gridSize.x; ++i)
1079 // y-axis
1080 s = vec2(vid_conwidth, 1);
1081 for (i = 1; i < 1 / hud_configure_gridSize.y; ++i)
1083 }
1084}
1085
1088{
1090 {
1091 if (isdemo() || intermission == 2 || scoreboard_active)
1092 {
1094 return;
1095 }
1096
1097 if (!hud_configure_prev)
1098 {
1099 hudShiftState = 0;
1100 for (int i = REGISTRY_COUNT(hud_panels) - 1; i >= 0; --i)
1101 REGISTRY_GET(hud_panels, panel_order[i]).update_time = time;
1102 }
1103
1104 // NOTE this check is necessary because _menu_alpha isn't updated the frame the menu gets enabled
1106 {
1107 if (autocvar__menu_alpha == 0)
1110 }
1111
1113 }
1114 else if (hud_configure_prev)
1115 {
1119 }
1120}
1121
1122const float hlBorderSize = 2;
1123const string hlBorder = "gfx/hud/default/border_highlighted";
1124const string hlBorder2 = "gfx/hud/default/border_highlighted2";
1125void HUD_Panel_HlBorder(float myBorder, vector color, float theAlpha)
1126{
1127 vector pos = panel_pos - vec2(myBorder, myBorder);
1128 drawfill(pos, panel_size + '2 2 0' * myBorder, '0 0.5 1', 0.5 * theAlpha, DRAWFLAG_NORMAL);
1129 drawpic_tiled(pos, hlBorder, '8 1 0' * hlBorderSize, vec2(panel_size.x + 2 * myBorder, hlBorderSize), color, theAlpha, DRAWFLAG_NORMAL);
1130 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);
1131 pos.y += hlBorderSize;
1132 drawpic_tiled(pos, hlBorder2, '1 8 0' * hlBorderSize, vec2(hlBorderSize, panel_size.y + 2 * myBorder - 2 * hlBorderSize), color, theAlpha, DRAWFLAG_NORMAL);
1133 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);
1134}
1135
1136void HUD_Panel_HlCenterLine(float myBorder)
1137{
1139 return;
1140 float panel_centerpos_x = panel_pos.x + panel_size.x * 0.5;
1142 for (int i = 0; i < n; ++i)
1143 {
1144 float xpos_rel = stof(argv(i));
1145 if (xpos_rel <= 0 || xpos_rel >= 1)
1146 continue;
1147 float ofs = fabs(panel_centerpos_x / vid_conwidth - xpos_rel);
1148 if (ofs < 0.02) // don't bother showing the center line if it's evident that the panel is not centered
1149 {
1150 float f = map_bound_ranges(ofs, 0.001, 0.01, 0, 1);
1151 vector col = '1 0 0' * f + '0 1 0' * (1 - f); // from red (far) to green (close)
1152 float theAlpha = 0.3 + 0.1 * sin(6 * time); // blink
1153 theAlpha *= (1 - autocvar__menu_alpha) * bound(0, hud_configure_centerline_time - time, 0.5) * 2; // fade
1154 vector pos = vec2(panel_centerpos_x - 1, panel_pos.y - myBorder);
1155 drawfill(pos, vec2(3, panel_size.y + 2 * myBorder), col, theAlpha, DRAWFLAG_NORMAL);
1156 }
1157 }
1158}
1159
1161{
1163 {
1164 if (tab_panel)
1165 {
1166 panel = tab_panel;
1168 drawfill(panel_pos - '1 1 0' * panel_bg_border, panel_size + '2 2 0' * panel_bg_border, '1 1 1', 0.2, DRAWFLAG_NORMAL);
1169 }
1170 if (highlightedPanel)
1171 {
1176 }
1177 }
1178}
var entity(vector mins, vector maxs,.entity tofield) findbox_tofield_OrFallback
void drawpic_tiled(vector pos, string pic, vector sz, vector area, vector color, float theAlpha, float drawflag)
Definition draw.qc:24
#define drawfill(position, size, rgb, alpha, flag)
Definition draw.qh:36
float autocvar_con_chatsize
Definition chat.qh:8
#define LABEL(id)
Definition compiler.qh:34
const float DRAWFLAG_NORMAL
const float FILE_WRITE
float time
float intermission
vector color
Definition dynlight.qc:15
entity highlightedPanel
Definition hud.qh:107
string autocvar_hud_dock
Definition hud.qh:192
vector panel_size
Definition hud.qh:163
float highlightedAction
Definition hud.qh:108
entity highlightedPanel_backup
Definition hud.qh:141
#define HUD_PANEL(NAME)
Definition hud.qh:52
vector panel_pos_backup
Definition hud.qh:142
vector panel_click_distance
Definition hud.qh:104
const int S_SHIFT
Definition hud.qh:129
int hudShiftState
Definition hud.qh:128
string autocvar__hud_panelorder
Definition hud.qh:189
const int S_ALT
Definition hud.qh:131
float autocvar__menu_alpha
Definition hud.qh:187
float hud_dynamic_shake_factor
Definition hud.qh:214
float panel_bg_padding
Definition hud.qh:174
string autocvar_hud_skin
Definition hud.qh:203
int panel_order[REGISTRY_MAX(hud_panels)]
Definition hud.qh:66
#define HUD_Panel_UpdatePosSize()
Definition hud.qh:428
float panel_bg_border
Definition hud.qh:172
float resizeCorner
Definition hud.qh:106
string hud_panelorder_prev
Definition hud.qh:67
vector panel_size_copied
Definition hud.qh:145
float panel_enabled
Definition hud.qh:161
vector panel_size_backup
Definition hud.qh:143
vector panel_pos
Definition hud.qh:162
const int PANEL_CONFIG_CANBEOFF
Definition hud.qh:238
vector mousepos
Definition hud.qh:103
entity panel
Definition hud.qh:147
const int PANEL_CONFIG_MAIN
Definition hud.qh:237
const int S_CTRL
Definition hud.qh:130
vector panel_click_resizeorigin
Definition hud.qh:105
void HUD_Panel_FirstInDrawQ(float id)
float tab_backward
void HUD_Panel_ExportCfg(string cfgname)
Definition hud_config.qc:10
void HUD_Panel_Mouse()
void reset_tab_panels()
void HUD_Panel_HlCenterLine(float myBorder)
int HUD_Panel_Check_Mouse_Pos(bool allow_move)
float pressed_key_time
vector tab_panel_pos
vector highlightedPanel_initial_pos
void HUD_Configure_DrawGrid()
entity tab_panels[REGISTRY_MAX(hud_panels)]
void HUD_Panel_HlBorder(float myBorder, vector color, float theAlpha)
vector HUD_Panel_CheckResize(vector mySize, vector resizeorigin)
void HUD_Panel_SetPosSize(vector mySize)
const float hlBorderSize
void HUD_Panel_Highlight(float allow_move)
float HUD_Panel_InputEvent(float bInputType, float nPrimary, float nSecondary)
void HUD_Configure_PostDraw()
float _menu_alpha_prev
vector highlightedPanel_initial_size
const string hlBorder2
void HUD_Panel_SetPos(vector pos)
void HUD_Panel_EnableMenu()
void HUD_Panel_Arrow_Action(float nPrimary)
const string hlBorder
vector HUD_Panel_CheckMove(vector myPos, vector mySize)
Definition hud_config.qc:98
entity tab_panel
void HUD_Configure_Exit_Force()
Definition hud_config.qc:86
void HUD_Configure_Frame()
vector hud_configure_gridSize
Definition hud_config.qh:20
float prevMouseClickedTime
Definition hud_config.qh:15
#define HUD_Write_Cvar(cvar)
Definition hud_config.qh:40
float hud_configure_prev
Definition hud_config.qh:18
const int S_MOUSE1
Definition hud_config.qh:10
float hud_configure_checkcollisions
Definition hud_config.qh:19
float autocvar_hud_configure_grid_alpha
Definition hud_config.qh:6
vector hud_configure_realGridSize
Definition hud_config.qh:21
string autocvar_hud_configure_vertical_lines
Definition hud_config.qh:7
bool autocvar__hud_configure
Definition hud_config.qh:3
int prevMouseClicked
Definition hud_config.qh:14
#define HUD_Write_PanelCvar(cvar_suf)
Definition hud_config.qh:41
bool autocvar_hud_configure_checkcollisions
Definition hud_config.qh:4
vector prevMouseClickedPos
Definition hud_config.qh:16
float hud_configure_centerline_time
Definition hud_config.qh:23
bool autocvar_hud_configure_grid
Definition hud_config.qh:5
int mouseClicked
Definition hud_config.qh:13
float hud_configure_menu_open
Definition hud_config.qh:22
const int S_MOUSE2
Definition hud_config.qh:11
#define HUD_Write(s)
Definition hud_config.qh:39
float K_SHIFT
Definition keycodes.qc:22
float K_UPARROW
Definition keycodes.qc:15
float K_BACKSPACE
Definition keycodes.qc:14
float K_DOWNARROW
Definition keycodes.qc:16
float K_MOUSE1
Definition keycodes.qc:129
float K_CTRL
Definition keycodes.qc:21
float K_RIGHTARROW
Definition keycodes.qc:18
float K_SPACE
Definition keycodes.qc:10
float K_ALT
Definition keycodes.qc:20
float K_ENTER
Definition keycodes.qc:8
float K_LEFTARROW
Definition keycodes.qc:17
float K_MOUSE2
Definition keycodes.qc:130
float K_KP_ENTER
Definition keycodes.qc:74
float K_TAB
Definition keycodes.qc:7
float K_ESCAPE
Definition keycodes.qc:9
float K_PAUSE
Definition keycodes.qc:78
noref float vid_conwidth
Definition draw.qh:8
noref float vid_conheight
Definition draw.qh:9
#define LOG_INFOF(...)
Definition log.qh:66
ERASEABLE float map_bound_ranges(float value, float src_min, float src_max, float dest_min, float dest_max)
Same as map_ranges except that values outside the source range are clamped to min or max.
Definition math.qh:372
void localcmd(string command,...)
void cvar_set(string name, string value)
float isdemo()
void fclose(float fhandle)
float stof(string val,...)
float bound(float min, float value, float max)
float cvar(string name)
float fopen(string filename, float mode)
float sin(float f)
float min(float f,...)
string ftos(float f)
float fabs(float f)
float floor(float f)
float tokenize(string s)
string argv(float n)
float max(float f,...)
strcat(_("^F4Countdown stopped!"), "\n^BG", _("Teams are too unbalanced."))
#define NULL
Definition post.qh:14
#define REGISTRY_COUNT(id)
Definition registry.qh:18
#define REGISTRY_GET(id, i)
Definition registry.qh:43
#define REGISTRY_MAX(id)
Definition registry.qh:17
bool scoreboard_active
Definition scoreboard.qh:16
vector
Definition self.qh:92
#define strcpy(this, s)
Definition string.qh:52
ERASEABLE string ftos_mindecimals(float number)
Converts a number to a string with the minimum number of decimals It assumes that an extreme accuracy...
Definition string.qh:497
const vector eY
Definition vector.qh:45
const vector eX
Definition vector.qh:44
#define vec2(...)
Definition vector.qh:90
const int CURSOR_RESIZE
Definition view.qh:116
const int CURSOR_MOVE
Definition view.qh:115
int cursor_type
Definition view.qh:113
const int CURSOR_RESIZE2
Definition view.qh:117
const int CURSOR_NORMAL
Definition view.qh:114