00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "ui_main.h"
00026 #include "ui_internal.h"
00027 #include "ui_input.h"
00028 #include "node/ui_node_abstractnode.h"
00029 #include "node/ui_node_window.h"
00030
00031 #include "../client.h"
00032
00033 #define WINDOWEXTRADATA(node) UI_EXTRADATA(node, windowExtraData_t)
00034 #define WINDOWEXTRADATACONST(node) UI_EXTRADATACONST(node, windowExtraData_t)
00035
00039 static cvar_t *mn_sys_main;
00040
00044 static cvar_t *mn_sys_active;
00045
00050 int UI_GetLastFullScreenWindow (void)
00051 {
00052
00053 int pos = ui_global.windowStackPos - 1;
00054 while (pos > 0) {
00055 if (UI_WindowIsFullScreen(ui_global.windowStack[pos]))
00056 break;
00057 pos--;
00058 }
00059
00060 return pos;
00061 }
00062
00069 void UI_MoveWindowOnTop (uiNode_t * window)
00070 {
00071 int i, j;
00072
00073 if (UI_WindowIsFullScreen(window))
00074 return;
00075
00076
00077 for (i = 0; i < ui_global.windowStackPos; i++) {
00078 if (ui_global.windowStack[i] == window)
00079 break;
00080 }
00081
00082
00083 for (j = i; j < ui_global.windowStackPos; j++) {
00084 if (UI_WindowIsFullScreen(ui_global.windowStack[j]))
00085 break;
00086 if (WINDOWEXTRADATA(window).parent != WINDOWEXTRADATA(ui_global.windowStack[j]).parent)
00087 break;
00088 }
00089 if (i + 1 == j)
00090 return;
00091
00092
00093 for (; i < j - 1; i++) {
00094 ui_global.windowStack[i] = ui_global.windowStack[i+1];
00095 }
00096
00097 ui_global.windowStack[i] = window;
00098 }
00099
00106 static void UI_DeleteWindowFromStack (uiNode_t *window)
00107 {
00108 int i;
00109
00110
00111 for (i = 0; i < ui_global.windowStackPos; i++) {
00112 if (ui_global.windowStack[i] == window)
00113 break;
00114 }
00115
00116
00117 if (i < ui_global.windowStackPos) {
00118 ui_global.windowStackPos--;
00119 for (; i < ui_global.windowStackPos; i++)
00120 ui_global.windowStack[i] = ui_global.windowStack[i + 1];
00121 UI_InvalidateMouse();
00122 }
00123 }
00124
00129 static inline int UI_GetWindowPositionFromStackByName (const char *name)
00130 {
00131 int i;
00132 for (i = 0; i < ui_global.windowStackPos; i++)
00133 if (!strcmp(ui_global.windowStack[i]->name, name))
00134 return i;
00135
00136 return -1;
00137 }
00138
00144 static inline void UI_InsertWindowIntoStack (uiNode_t *window, int position)
00145 {
00146 int i;
00147 assert(position <= ui_global.windowStackPos);
00148 assert(position > 0);
00149 assert(window != NULL);
00150
00151
00152 for (i = ui_global.windowStackPos; i > position; i--) {
00153 ui_global.windowStack[i] = ui_global.windowStack[i - 1];
00154 }
00155
00156 ui_global.windowStack[position] = window;
00157 ui_global.windowStackPos++;
00158 }
00159
00167 static uiNode_t* UI_PushWindowDelete (const char *name, const char *parent, qboolean delete)
00168 {
00169 uiNode_t *window;
00170
00171 UI_ReleaseInput();
00172
00173 window = UI_GetWindow(name);
00174 if (window == NULL) {
00175 Com_Printf("Window \"%s\" not found.\n", name);
00176 return NULL;
00177 }
00178
00179
00180 if (delete)
00181 UI_DeleteWindowFromStack(window);
00182
00183 if (ui_global.windowStackPos < UI_MAX_WINDOWSTACK)
00184 if (parent) {
00185 const int parentPos = UI_GetWindowPositionFromStackByName(parent);
00186 if (parentPos == -1) {
00187 Com_Printf("Didn't find parent window \"%s\" for window push of \"%s\"\n", parent, name);
00188 return NULL;
00189 }
00190 UI_InsertWindowIntoStack(window, parentPos + 1);
00191 WINDOWEXTRADATA(window).parent = ui_global.windowStack[parentPos];
00192 } else
00193 ui_global.windowStack[ui_global.windowStackPos++] = window;
00194 else
00195 Com_Printf("Window stack overflow\n");
00196
00197 if (window->behaviour->init) {
00198 window->behaviour->init(window);
00199 }
00200
00201
00202 Key_SetDest(key_game);
00203
00204 UI_InvalidateMouse();
00205 return window;
00206 }
00207
00214 int UI_CompleteWithWindow (const char *partial, const char **match)
00215 {
00216 int i;
00217 int matches = 0;
00218 const char *localMatch[MAX_COMPLETE];
00219 const size_t len = strlen(partial);
00220
00221 if (len == 0) {
00222 for (i = 0; i < ui_global.numWindows; i++)
00223 Com_Printf("%s\n", ui_global.windows[i]->name);
00224 return 0;
00225 }
00226
00227
00228 for (i = 0; i < ui_global.numWindows; i++)
00229 if (!strncmp(partial, ui_global.windows[i]->name, len)) {
00230 Com_Printf("%s\n", ui_global.windows[i]->name);
00231 localMatch[matches++] = ui_global.windows[i]->name;
00232 if (matches >= MAX_COMPLETE) {
00233 Com_Printf("UI_CompleteWithWindow: hit MAX_COMPLETE\n");
00234 break;
00235 }
00236 }
00237
00238 return Cmd_GenericCompleteFunction(len, match, matches, localMatch);
00239 }
00240
00247 uiNode_t* UI_PushWindow (const char *name, const char *parentName)
00248 {
00249 return UI_PushWindowDelete(name, parentName, qtrue);
00250 }
00251
00256 static void UI_PushChildWindow_f (void)
00257 {
00258 if (Cmd_Argc() > 1)
00259 UI_PushWindow(Cmd_Argv(1), Cmd_Argv(2));
00260 else
00261 Com_Printf("Usage: %s <name> <parentname>\n", Cmd_Argv(0));
00262 }
00263
00268 static void UI_PushWindow_f (void)
00269 {
00270 if (Cmd_Argc() > 1)
00271 UI_PushWindow(Cmd_Argv(1), NULL);
00272 else
00273 Com_Printf("Usage: %s <name>\n", Cmd_Argv(0));
00274 }
00275
00284 static void UI_PushDropDownWindow_f (void)
00285 {
00286 vec2_t source;
00287 vec2_t destination;
00288 uiNode_t *node;
00289 int direction;
00290 size_t writtenBytes;
00291 int result;
00292
00293 if (Cmd_Argc() != 4 && Cmd_Argc() != 5) {
00294 Com_Printf("Usage: %s <source-anchor> <point-in-source-anchor> <dest-anchor> <point-in-dest-anchor>\n", Cmd_Argv(0));
00295 return;
00296 }
00297
00298
00299 node = UI_GetNodeByPath(Cmd_Argv(1));
00300 if (node == NULL) {
00301 Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(1));
00302 return;
00303 }
00304 result = Com_ParseValue(&direction, Cmd_Argv(2), V_INT, 0, sizeof(direction), &writtenBytes);
00305 if (result != RESULT_OK) {
00306 Com_Printf("UI_PushDropDownWindow_f: '%s' in not a V_INT\n", Cmd_Argv(2));
00307 return;
00308 }
00309 UI_NodeGetPoint(node, source, direction);
00310 UI_NodeRelativeToAbsolutePoint(node, source);
00311
00312
00313 if (!strcmp(Cmd_Argv(4), "mouse")) {
00314 destination[0] = mousePosX;
00315 destination[1] = mousePosY;
00316 } else {
00317
00318 node = UI_GetNodeByPath(Cmd_Argv(3));
00319 if (node == NULL) {
00320 Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(3));
00321 return;
00322 }
00323 result = Com_ParseValue(&direction, Cmd_Argv(4), V_INT, 0, sizeof(direction), &writtenBytes);
00324 if (result != RESULT_OK) {
00325 Com_Printf("UI_PushDropDownWindow_f: '%s' in not a V_INT\n", Cmd_Argv(4));
00326 return;
00327 }
00328 UI_NodeGetPoint(node, destination, direction);
00329 UI_NodeRelativeToAbsolutePoint(node, destination);
00330 }
00331
00332
00333 node = UI_GetNodeByPath(Cmd_Argv(1));
00334 if (node == NULL) {
00335 Com_Printf("UI_PushDropDownWindow_f: Node '%s' doesn't exist\n", Cmd_Argv(1));
00336 return;
00337 }
00338 node = node->root;
00339 node->pos[0] += destination[0] - source[0];
00340 node->pos[1] += destination[1] - source[1];
00341 UI_PushWindow(node->name, NULL);
00342 }
00343
00349 static void UI_PushNoHud_f (void)
00350 {
00351
00352 if (!CL_BattlescapeRunning())
00353 return;
00354
00355 UI_PushWindow("nohud", NULL);
00356 }
00357
00358 static void UI_RemoveWindowAtPositionFromStack (int position)
00359 {
00360 int i;
00361 assert(position < ui_global.windowStackPos);
00362 assert(position >= 0);
00363
00364
00365 for (i = position; i < ui_global.windowStackPos; i++) {
00366 ui_global.windowStack[i] = ui_global.windowStack[i + 1];
00367 }
00368 ui_global.windowStack[ui_global.windowStackPos--] = NULL;
00369 }
00370
00371 static void UI_CloseAllWindow (void)
00372 {
00373 int i;
00374 for (i = ui_global.windowStackPos - 1; i >= 0; i--) {
00375 uiNode_t *window = ui_global.windowStack[i];
00376
00377 if (window->behaviour->close)
00378 window->behaviour->close(window);
00379
00380
00381 WINDOWEXTRADATA(window).parent = NULL;
00382 ui_global.windowStackPos--;
00383 ui_global.windowStack[ui_global.windowStackPos] = NULL;
00384 }
00385 }
00386
00400 void UI_InitStack (const char* activeWindow, const char* mainWindow, qboolean popAll, qboolean pushActive)
00401 {
00402 if (popAll)
00403 UI_PopWindow(qtrue);
00404 if (activeWindow) {
00405 Cvar_Set("mn_sys_active", activeWindow);
00406
00407 if (ui_global.numWindows != 0) {
00408 if (pushActive)
00409 UI_PushWindow(activeWindow, NULL);
00410 }
00411 }
00412
00413 if (mainWindow)
00414 Cvar_Set("mn_sys_main", mainWindow);
00415 }
00416
00420 qboolean UI_IsWindowOnStack (const char* name)
00421 {
00422 return UI_GetWindowPositionFromStackByName(name) != -1;
00423 }
00424
00428 static void UI_CloseWindowByRef (uiNode_t *window)
00429 {
00430 int i;
00431
00433 UI_ReleaseInput();
00434
00435 assert(ui_global.windowStackPos);
00436 i = UI_GetWindowPositionFromStackByName(window->name);
00437 if (i == -1) {
00438 Com_Printf("Window '%s' is not on the active stack\n", window->name);
00439 return;
00440 }
00441
00442
00443 while (i + 1 < ui_global.windowStackPos) {
00444 uiNode_t *m = ui_global.windowStack[i + 1];
00445 if (WINDOWEXTRADATA(m).parent != window) {
00446 break;
00447 }
00448 if (window->behaviour->close)
00449 window->behaviour->close(window);
00450 WINDOWEXTRADATA(m).parent = NULL;
00451 UI_RemoveWindowAtPositionFromStack(i + 1);
00452 }
00453
00454
00455 if (window->behaviour->close)
00456 window->behaviour->close(window);
00457 WINDOWEXTRADATA(window).parent = NULL;
00458 UI_RemoveWindowAtPositionFromStack(i);
00459
00460 UI_InvalidateMouse();
00461 }
00462
00463 void UI_CloseWindow (const char* name)
00464 {
00465 uiNode_t *window = UI_GetWindow(name);
00466 if (window == NULL) {
00467 Com_Printf("Window '%s' not found\n", name);
00468 return;
00469 }
00470
00471
00472 UI_CloseWindowByRef(window);
00473 }
00474
00480 void UI_PopWindow (qboolean all)
00481 {
00482 uiNode_t *oldfirst = ui_global.windowStack[0];
00483
00484 if (all) {
00485 UI_CloseAllWindow();
00486 } else {
00487 uiNode_t *mainWindow = ui_global.windowStack[ui_global.windowStackPos - 1];
00488 if (!ui_global.windowStackPos)
00489 return;
00490 if (WINDOWEXTRADATA(mainWindow).parent)
00491 mainWindow = WINDOWEXTRADATA(mainWindow).parent;
00492 UI_CloseWindowByRef(mainWindow);
00493
00494 if (ui_global.windowStackPos == 0) {
00495
00496
00497
00498 if (!strcmp(oldfirst->name, mn_sys_main->string)) {
00499 if (mn_sys_active->string[0] != '\0')
00500 UI_PushWindow(mn_sys_active->string, NULL);
00501 if (!ui_global.windowStackPos)
00502 UI_PushWindow(mn_sys_main->string, NULL);
00503 } else {
00504 if (mn_sys_main->string[0] != '\0')
00505 UI_PushWindow(mn_sys_main->string, NULL);
00506 if (!ui_global.windowStackPos)
00507 UI_PushWindow(mn_sys_active->string, NULL);
00508 }
00509 }
00510 }
00511
00512
00513 Key_SetDest(key_game);
00514 }
00515
00520 static void UI_CloseWindow_f (void)
00521 {
00522 if (Cmd_Argc() != 2) {
00523 Com_Printf("Usage: %s <name>\n", Cmd_Argv(0));
00524 return;
00525 }
00526
00527 UI_CloseWindow(Cmd_Argv(1));
00528 }
00529
00530 void UI_PopWindowWithEscKey (void)
00531 {
00532 const uiNode_t *window = ui_global.windowStack[ui_global.windowStackPos - 1];
00533
00534
00535 if (ui_global.windowStackPos == 0)
00536 return;
00537
00538
00539 if (WINDOWEXTRADATACONST(window).preventTypingEscape)
00540 return;
00541
00542 UI_PopWindow(qfalse);
00543 }
00544
00549 static void UI_PopWindow_f (void)
00550 {
00551 if (Cmd_Argc() > 1) {
00552 Com_Printf("Usage: %s\n", Cmd_Argv(0));
00553 return;
00554 }
00555
00556 UI_PopWindow(qfalse);
00557 }
00558
00564 uiNode_t* UI_GetActiveWindow (void)
00565 {
00566 return (ui_global.windowStackPos > 0 ? ui_global.windowStack[ui_global.windowStackPos - 1] : NULL);
00567 }
00568
00572 void UI_GetActiveRenderRect (int *x, int *y, int *width, int *height)
00573 {
00574 uiNode_t *window = UI_GetActiveWindow();
00575
00577 if (!window || !WINDOWEXTRADATA(window).renderNode)
00578 if (UI_IsWindowOnStack(mn_hud->string))
00579 window = UI_GetWindow(mn_hud->string);
00580
00581 if (window && WINDOWEXTRADATA(window).renderNode) {
00582 uiNode_t* node = WINDOWEXTRADATA(window).renderNode;
00583 vec2_t pos;
00584
00585 UI_Validate(window);
00586
00587 UI_GetNodeAbsPos(node, pos);
00588 *x = pos[0] * viddef.rx;
00589 *y = pos[1] * viddef.ry;
00590 *width = node->size[0] * viddef.rx;
00591 *height = node->size[1] * viddef.ry;
00592 } else {
00593 *x = 0;
00594 *y = 0;
00595 *width = 0;
00596 *height = 0;
00597 }
00598 }
00599
00605 const char* UI_GetActiveWindowName (void)
00606 {
00607 const uiNode_t* window = UI_GetActiveWindow();
00608 if (window == NULL)
00609 return "";
00610 return window->name;
00611 }
00612
00617 qboolean UI_IsPointOnWindow (void)
00618 {
00619 const uiNode_t *hovered;
00620
00621 if (UI_GetMouseCapture() != NULL)
00622 return qtrue;
00623
00624 if (ui_global.windowStackPos != 0) {
00625 if (WINDOWEXTRADATA(ui_global.windowStack[ui_global.windowStackPos - 1]).dropdown)
00626 return qtrue;
00627 }
00628
00629 hovered = UI_GetHoveredNode();
00630 if (hovered) {
00631
00632 if (hovered->root && hovered == WINDOWEXTRADATACONST(hovered->root).renderNode) {
00633 return qfalse;
00634 }
00635 return qtrue;
00636 }
00637
00638 return qtrue;
00639 }
00640
00648 uiNode_t *UI_GetWindow (const char *name)
00649 {
00650 unsigned char min = 0;
00651 unsigned char max = ui_global.numWindows;
00652
00653 while (min != max) {
00654 const int mid = (min + max) >> 1;
00655 const char diff = strcmp(ui_global.windows[mid]->name, name);
00656 assert(mid < max);
00657 assert(mid >= min);
00658
00659 if (diff == 0)
00660 return ui_global.windows[mid];
00661
00662 if (diff > 0)
00663 max = mid;
00664 else
00665 min = mid + 1;
00666 }
00667
00668 return NULL;
00669 }
00670
00674 void UI_InvalidateStack (void)
00675 {
00676 int pos;
00677 for (pos = 0; pos < ui_global.windowStackPos; pos++) {
00678 UI_Invalidate(ui_global.windowStack[pos]);
00679 }
00680 Cvar_SetValue("mn_sys_screenwidth", viddef.virtualWidth);
00681 Cvar_SetValue("mn_sys_screenheight", viddef.virtualHeight);
00682 }
00683
00688 void UI_SetNewWindowPos (uiNode_t* window, int x, int y)
00689 {
00690 if (window)
00691 Vector2Set(window->pos, x, y);
00692 }
00693
00698 void UI_InsertWindow (uiNode_t* window)
00699 {
00700 int pos = 0;
00701 int i;
00702
00703 if (ui_global.numWindows >= UI_MAX_WINDOWS)
00704 Com_Error(ERR_FATAL, "UI_InsertWindow: hit UI_MAX_WINDOWS");
00705
00706
00707 for (pos = 0; pos < ui_global.numWindows; pos++) {
00708 const uiNode_t* node = ui_global.windows[pos];
00709 if (strcmp(window->name, node->name) < 0)
00710 break;
00711 }
00712
00713
00714 for (i = ui_global.numWindows - 1; i >= pos; i--)
00715 ui_global.windows[i + 1] = ui_global.windows[i];
00716
00717
00718 ui_global.windows[pos] = window;
00719 ui_global.numWindows++;
00720 }
00721
00725 static void UI_SetNewWindowPos_f (void)
00726 {
00727 uiNode_t* window = UI_GetActiveWindow();
00728
00729 if (Cmd_Argc() < 3)
00730 Com_Printf("Usage: %s <x> <y>\n", Cmd_Argv(0));
00731
00732 UI_SetNewWindowPos(window, atoi(Cmd_Argv(1)), atoi(Cmd_Argv(2)));
00733 }
00734
00740 static void UI_FireInit_f (void)
00741 {
00742 uiNode_t* window;
00743
00744 if (Cmd_Argc() != 2) {
00745 Com_Printf("Usage: %s <window>\n", Cmd_Argv(0));
00746 return;
00747 }
00748
00749 window = UI_GetNodeByPath(Cmd_Argv(1));
00750 if (window == NULL) {
00751 Com_Printf("UI_FireInit_f: Node '%s' not found\n", Cmd_Argv(1));
00752 return;
00753 }
00754
00755 if (!UI_NodeInstanceOf(window, "window")) {
00756 Com_Printf("UI_FireInit_f: Node '%s' is not a 'window'\n", Cmd_Argv(1));
00757 return;
00758 }
00759
00760
00761 if (window) {
00762 if (WINDOWEXTRADATACONST(window).onInit)
00763 UI_ExecuteEventActions(window, WINDOWEXTRADATACONST(window).onInit);
00764 Com_DPrintf(DEBUG_CLIENT, "Reinitialize %s\n", window->name);
00765 }
00766 }
00767
00768 static void UI_InitStack_f (void) {
00769 const char *mainWindow;
00770 const char *optionWindow = NULL;
00771
00772 if (Cmd_Argc() < 2) {
00773 Com_Printf("Usage: %s <mainwindow> [<optionwindow>]\n", Cmd_Argv(0));
00774 return;
00775 }
00776
00777 mainWindow = Cmd_Argv(1);
00778 if (Cmd_Argc() == 3) {
00779 optionWindow = Cmd_Argv(2);
00780 }
00781
00782 UI_InitStack(mainWindow, optionWindow, qtrue, qtrue);
00783 }
00784
00788 static void UI_DebugTree (const uiNode_t *node, int depth)
00789 {
00790 const uiNode_t *child = node->firstChild;
00791 int i;
00792
00793 for (i = 0; i < depth; i++) {
00794 Com_Printf(" ");
00795 }
00796 Com_Printf("+ %s %s\n", node->behaviour->name, node->name);
00797
00798 while (child) {
00799 UI_DebugTree(child, depth + 1);
00800 child = child->next;
00801 }
00802 }
00803
00804 static void UI_DebugTree_f (void)
00805 {
00806 const char *window;
00807 const uiNode_t *node;
00808
00809 if (Cmd_Argc() != 2) {
00810 Com_Printf("Usage: %s <mainwindow>\n", Cmd_Argv(0));
00811 return;
00812 }
00813
00814 window = Cmd_Argv(1);
00815 node = UI_GetWindow(window);
00816 UI_DebugTree(node, 0);
00817 }
00818
00819 void UI_InitWindows (void)
00820 {
00821 mn_sys_main = Cvar_Get("mn_sys_main", "", 0, "This is the main window id that is at the very first window stack - also see mn_sys_active");
00822 mn_sys_active = Cvar_Get("mn_sys_active", "", 0, "The active window we will return to when hitting esc once - also see mn_sys_main");
00823
00824
00825 Cmd_AddCommand("mn_fireinit", UI_FireInit_f, "Call the init function of a window");
00826 Cmd_AddCommand("mn_push", UI_PushWindow_f, "Push a window to the window stack");
00827 Cmd_AddParamCompleteFunction("mn_push", UI_CompleteWithWindow);
00828 Cmd_AddCommand("mn_push_dropdown", UI_PushDropDownWindow_f, "Push a dropdown window at a position");
00829 Cmd_AddCommand("mn_push_child", UI_PushChildWindow_f, "Push a window to the windowstack with a big dependancy to a parent window");
00830 Cmd_AddCommand("mn_pop", UI_PopWindow_f, "Pops the current window from the stack");
00831 Cmd_AddCommand("mn_close", UI_CloseWindow_f, "Close a window");
00832 Cmd_AddCommand("mn_move", UI_SetNewWindowPos_f, "Moves the window to a new position.");
00833 Cmd_AddCommand("mn_initstack", UI_InitStack_f, "Initialize the window stack with a main and an option window.");
00834
00835 Cmd_AddCommand("mn_tree", UI_DebugTree_f, "Display a tree of nodes fropm a window into the console.");
00836 Cmd_AddParamCompleteFunction("mn_tree", UI_CompleteWithWindow);
00837
00839 Cmd_AddCommand("hidehud", UI_PushNoHud_f, _("Hide the HUD (press ESC to reactivate HUD)"));
00840 }