void UI_CloseWindow (const char* name) { uiNode_t *window = UI_GetWindow(name); if (window == NULL) { Com_Printf("Window '%s' not found\n", name); return; } /* found the correct add it to stack or bring it on top */ UI_CloseWindowByRef(window); }
static void UI_DebugTree_f (void) { const char *window; const uiNode_t *node; if (Cmd_Argc() != 2) { Com_Printf("Usage: %s <mainwindow>\n", Cmd_Argv(0)); return; } window = Cmd_Argv(1); node = UI_GetWindow(window); UI_DebugTree(node, 0); }
/** * @brief Generates a popup that contains up to 3 buttons. * @param[in] title Title of the popup. * @param[in] text Text to display in the popup (use popupText if text is NULL). * @param[in] clickAction1 Action to perform when one clicked on the first button. * @param[in] clickText1 String that will be written in first button. * @param[in] tooltip1 Tooltip of first button. * @param[in] clickAction2 Action to perform when one clicked on the second button. * @param[in] clickText2 String that will be written in second button. * @param[in] tooltip2 Tooltip of second button. * @param[in] clickAction3 Action to perform when one clicked on the third button. * @param[in] clickText3 String that will be written in third button. * @param[in] tooltip3 Tooltip of third button. * @note clickAction AND clickText must be NULL if button should be invisible. */ void UI_PopupButton (const char *title, const char *text, const char *clickAction1, const char *clickText1, const char *tooltip1, const char *clickAction2, const char *clickText2, const char *tooltip2, const char *clickAction3, const char *clickText3, const char *tooltip3) { uiNode_t* window; Cvar_Set("ui_sys_popup_title", title); if (text) UI_RegisterText(TEXT_POPUP_INFO, text); else UI_RegisterText(TEXT_POPUP_INFO, popupText); window = UI_GetWindow(POPUPBUTTON_WINDOW_NAME); if (!window) Com_Error(ERR_FATAL, "Could not get \""POPUPBUTTON_WINDOW_NAME"\" window"); Cvar_Set("ui_sys_popup_button_text1", clickText1); Cvar_Set("ui_sys_popup_button_tooltip1", tooltip1); if (!clickAction1 && !clickText1) { UI_SetOneButton(window, va("%s1", POPUPBUTTON_NODE_NAME), NULL); } else { UI_SetOneButton(window, va("%s1", POPUPBUTTON_NODE_NAME), clickAction1 ? clickAction1 : popupAction1); } Cvar_Set("ui_sys_popup_button_text2", clickText2); Cvar_Set("ui_sys_popup_button_tooltip2", tooltip2); if (!clickAction2 && !clickText2) { UI_SetOneButton(window, va("%s2", POPUPBUTTON_NODE_NAME), NULL); } else { UI_SetOneButton(window, va("%s2", POPUPBUTTON_NODE_NAME), clickAction2 ? clickAction2 : popupAction2); } Cvar_Set("ui_sys_popup_button_text3", clickText3); Cvar_Set("ui_sys_popup_button_tooltip3", tooltip3); if (!clickAction3 && !clickText3) { UI_SetOneButton(window, va("%s3", POPUPBUTTON_NODE_NAME), NULL); } else { UI_SetOneButton(window, va("%s3", POPUPBUTTON_NODE_NAME), clickAction3 ? clickAction3 : popupAction3); } if (!UI_IsWindowOnStack(window->name)) UI_PushWindow(window->name, NULL, NULL); }
/** * @note not moved into V_UI_NODEMETHOD because it is more a generic * tool than a method of the node editor */ static void UI_EditorNodeExtract_f (void) { if (Cmd_Argc() != 2) { Com_Printf("Usage: %s <windowname>\n", Cmd_Argv(0)); return; } uiNode_t* window = UI_GetWindow(Cmd_Argv(1)); if (!window) { Com_Printf("Window '%s' not found\n", Cmd_Argv(1)); return; } ScopedFile file; FS_OpenFile(va("window_%s_extracted.ufo", window->name), &file, FILE_WRITE); UI_EditorNodeExtractNode(&file, window, 0); Com_Printf("Window '%s' extracted.\n", Cmd_Argv(1)); }
/** * @brief after execution of a unittest window, it analyse color of * normalized indicator, and create asserts. Both Fail/Pass asserts is * useful to count number. */ static void UFO_AnalyseTestWindow (const char* windowName) { const uiBehaviour_t* stringBehaviour = UI_GetNodeBehaviour("string"); const uiNode_t* node; const uiNode_t* window = UI_GetWindow(windowName); CU_ASSERT_FATAL(window != nullptr); CU_ASSERT_FATAL(stringBehaviour != nullptr); for (node = window->firstChild; node != nullptr; node = node->next) { bool isGreen; bool isRed; /* skip non "string" nodes */ if (node->behaviour != stringBehaviour) continue; if (node->invis) continue; /* skip nodes without "test" prefix */ if (!Q_strstart(node->name, "test")) continue; isGreen = node->color[0] < 0.1 && node->color[1] > 0.9 && node->color[2] < 0.1; isRed = node->color[0] > 0.9 && node->color[1] < 0.1 && node->color[2] < 0.1; if (isGreen) { /** @note Useful to count number of tests */ CU_ASSERT_TRUE(true); } else if (isRed) { const char* message = va("%s.%s failed.", windowName, node->name); /*Com_Printf("Error: %s\n", message);*/ /*CU_FAIL(message);*/ CU_assertImplementation(CU_FALSE, 0, va("CU_FAIL(%s)", message), va("base/ufos/uitest/%s.ufo", windowName), "", CU_FALSE); } else { const char* message = va("%s.%s have an unknown status.", windowName, node->name); /*Com_Printf("Warning: %s\n", message);*/ /*CU_FAIL(message);*/ CU_assertImplementation(CU_FALSE, 0, va("CU_FAIL(%s)", message), va("base/ufos/uitest/%s.ufo", windowName), "", CU_FALSE); } } }
/** * @brief Generates a popup that contains a list of selectable choices. * @param[in] title Title of the popup. * @param[in] headline First line of text written in the popup. * @param[in] entries List of the selectables choices. * @param[in] clickAction Action to perform when one clicked on the popup. */ uiNode_t *UI_PopupList (const char *title, const char *headline, linkedList_t* entries, const char *clickAction) { uiNode_t* window; uiNode_t* listNode; Cvar_Set("ui_sys_popup_title", title); UI_RegisterText(TEXT_POPUP_INFO, headline); /* make sure, that we are using the linked list */ UI_ResetData(TEXT_LIST); UI_RegisterLinkedListText(TEXT_LIST, entries); window = UI_GetWindow(POPUPLIST_WINDOW_NAME); if (!window) Com_Error(ERR_FATAL, "Could not get "POPUPLIST_WINDOW_NAME" window"); listNode = UI_GetNode(window, POPUPLIST_NODE_NAME); if (!listNode) Com_Error(ERR_FATAL, "Could not get "POPUPLIST_NODE_NAME" node in "POPUPLIST_WINDOW_NAME" window"); /* free previous actions */ if (listNode->onClick) { assert(listNode->onClick->d.terminal.d1.data); Mem_Free(listNode->onClick->d.terminal.d1.data); Mem_Free(listNode->onClick); listNode->onClick = NULL; } if (clickAction) { UI_PoolAllocAction(&listNode->onClick, EA_CMD, clickAction); } else { listNode->onClick = NULL; } if (!UI_IsWindowOnStack(window->name)) UI_PushWindow(window->name, NULL, NULL); return listNode; }
/** * @brief Push a window onto the window stack * @param[in] name Name of the window to push onto window stack * @param[in] parentName Window name to link as parent-child (else NULL) * @param[in] params List of string parameters to send to the onWindowOpened method. * It can be NULL when there is no parameters, else this object must be freed by the caller. * @return A pointer to @c uiNode_t */ uiNode_t* UI_PushWindow (const char *name, const char *parentName, linkedList_t *params) { uiNode_t *window; UI_ReleaseInput(); window = UI_GetWindow(name); if (window == NULL) { Com_Printf("Window \"%s\" not found.\n", name); return NULL; } UI_DeleteWindowFromStack(window); if (ui_global.windowStackPos < UI_MAX_WINDOWSTACK) if (parentName) { const int parentPos = UI_GetWindowPositionFromStackByName(parentName); if (parentPos == -1) { Com_Printf("Didn't find parent window \"%s\" for window push of \"%s\"\n", parentName, name); return NULL; } UI_InsertWindowIntoStack(window, parentPos + 1); WINDOWEXTRADATA(window).parent = ui_global.windowStack[parentPos]; } else ui_global.windowStack[ui_global.windowStackPos++] = window; else Com_Printf("Window stack overflow\n"); UI_Node_WindowOpened(window, params); /* change from e.g. console mode to game input mode (fetch input) */ Key_SetDest(key_game); UI_InvalidateMouse(); return window; }
/** * @brief Parse a window * @sa CL_ParseClientData * @code * window windowName { * } * @endcode */ bool UI_ParseWindow (const char* type, const char* name, const char** text) { const char* errhead = "UI_ParseWindow: unexpected end of file (window"; uiNode_t* window; const char* token; int i; if (!Q_streq(type, "window")) { Com_Error(ERR_FATAL, "UI_ParseWindow: '%s %s' is not a window node\n", type, name); return false; /* never reached */ } if (!UI_TokenIsName(name, Com_GetType(text) == TT_QUOTED_WORD)) { Com_Printf("UI_ParseWindow: \"%s\" is not a well formed node name ([a-zA-Z_][a-zA-Z0-9_]*)\n", name); return false; } if (UI_TokenIsReserved(name)) { Com_Printf("UI_ParseWindow: \"%s\" is a reserved token, we can't call a node with it (node \"%s\")\n", name, name); return false; } /* search for windows with same name */ for (i = 0; i < ui_global.numWindows; i++) if (!strncmp(name, ui_global.windows[i]->name, sizeof(ui_global.windows[i]->name))) break; if (i < ui_global.numWindows) { Com_Printf("UI_ParseWindow: %s \"%s\" with same name found, second ignored\n", type, name); } if (ui_global.numWindows >= UI_MAX_WINDOWS) { Com_Error(ERR_FATAL, "UI_ParseWindow: max windows exceeded (%i) - ignore '%s'\n", UI_MAX_WINDOWS, name); return false; /* never reached */ } /* get window body */ token = Com_Parse(text); /* does this window inherit data from another window? */ if (Q_streq(token, "extends")) { uiNode_t* superWindow; token = Com_Parse(text); superWindow = UI_GetWindow(token); if (superWindow == nullptr) Sys_Error("Could not get the super window \"%s\"", token); window = UI_CloneNode(superWindow, nullptr, true, name, false); token = Com_Parse(text); } else { window = UI_AllocNode(name, type, false); window->root = window; } UI_InsertWindow(window); /* parse it's body */ bool result = UI_ParseNodeBody(window, text, &token, errhead); if (!result) { Com_Error(ERR_FATAL, "UI_ParseWindow: window \"%s\" has a bad body\n", window->name); } UI_Node_Loaded(window); return true; }
/** * @brief Read a path and return every we can use (node and property) * @details The path token must be a window name, and then node child. * Reserved token 'root' and 'parent' can be used to navigate. * If relativeNode is set, the path can start with reserved token * 'this', 'root' and 'parent' (relative to this node). * The function can return a node property by using a '\@', * the path 'foo\@pos' will return the window foo and the property 'pos' * from the 'window' behaviour. * @param[in] path Path to read. Contain a node location with dot seprator and a facultative property * @param[in] relativeNode relative node where the path start. It allow to use facultative command to start the path (this, parent, root). * @param[out] resultNode Node found. Else NULL. * @param[out] resultProperty Property found. Else NULL. * TODO Speed up, evilly used function, use strncmp instead of using buffer copy (name[MAX_VAR]) */ void UI_ReadNodePath (const char* path, const uiNode_t *relativeNode, uiNode_t **resultNode, const value_t **resultProperty) { char name[MAX_VAR]; uiNode_t* node = NULL; const char* nextName; char nextCommand = '^'; *resultNode = NULL; if (resultProperty) *resultProperty = NULL; nextName = path; while (nextName && nextName[0] != '\0') { const char* begin = nextName; char command = nextCommand; nextName = strpbrk(begin, ".@#"); if (!nextName) { Q_strncpyz(name, begin, sizeof(name)); nextCommand = '\0'; } else { assert(nextName - begin + 1 <= sizeof(name)); Q_strncpyz(name, begin, nextName - begin + 1); nextCommand = *nextName; nextName++; } switch (command) { case '^': /* first string */ if (Q_streq(name, "this")) { if (relativeNode == NULL) return; /** @todo find a way to fix the bad cast. only here to remove "discards qualifiers" warning */ node = *(uiNode_t**) ((void*)&relativeNode); } else if (Q_streq(name, "parent")) { if (relativeNode == NULL) return; node = relativeNode->parent; } else if (Q_streq(name, "root")) { if (relativeNode == NULL) return; node = relativeNode->root; } else node = UI_GetWindow(name); break; case '.': /* child node */ if (Q_streq(name, "parent")) node = node->parent; else if (Q_streq(name, "root")) node = node->root; else node = UI_GetNode(node, name); break; case '#': /* window index */ /** @todo FIXME use a warning instead of an assert */ assert(node->behaviour == ui_windowBehaviour); node = UI_WindowNodeGetIndexedChild(node, name); break; case '@': /* property */ assert(nextCommand == '\0'); *resultProperty = UI_GetPropertyFromBehaviour(node->behaviour, name); *resultNode = node; return; } if (!node) return; } *resultNode = node; return; }
/** * @brief Read a path and return every we can use (node and property) * @details The path token must be a window name, and then node child. * Reserved token 'root' and 'parent' can be used to navigate. * If relativeNode is set, the path can start with reserved token * 'this', 'root', 'parent' and 'child' (relative to this node). * The function can return a node property by using a '\@', * the path 'foo\@pos' will return the window foo and the property 'pos' * from the 'window' behaviour. * @param[in] path Path to read. Contain a node location with dot seprator and a facultative property * @param[in] relativeNode relative node where the path start. It allow to use facultative command to start the path (this, parent, root). * @param[in] iterationNode relative node referencing child in 'forchildin' iteration, mapped to '*node:child', can be nullptr * @param[out] resultNode Node found. Else nullptr. * @param[out] resultProperty Property found. Else nullptr. * @param[in,out] luaMethod A pointer to a value_t structure that is filled with a lua based method identification, can be nullptr * @note If luaMethod is set, the method will scan the known lua methods defined on the behaviour. If luaMethod is not set, only * registered local properties are scanned. * @todo Speed up, evilly used function, use strncmp instead of using buffer copy (name[MAX_VAR]) * @note If luaMethod is set, make sure to release the allocated .name string. */ void UI_ReadNodePath (const char* path, const uiNode_t* relativeNode, const uiNode_t* iterationNode, uiNode_t** resultNode, const value_t** resultProperty, value_t *luaMethod) { char name[MAX_VAR]; uiNode_t* node = nullptr; uiNode_t* childnode = nullptr; const char* nextName; char nextCommand = '^'; *resultNode = nullptr; if (resultProperty) *resultProperty = nullptr; nextName = path; while (nextName && nextName[0] != '\0') { const char* begin = nextName; char command = nextCommand; nextName = strpbrk(begin, ".@#"); if (!nextName) { Q_strncpyz(name, begin, sizeof(name)); nextCommand = '\0'; } else { assert(nextName - begin + 1 <= sizeof(name)); Q_strncpyz(name, begin, nextName - begin + 1); nextCommand = *nextName; nextName++; } switch (command) { case '^': /* first string */ if (Q_streq(name, "this")) { if (relativeNode == nullptr) return; node = const_cast<uiNode_t *>(relativeNode); } else if (Q_streq(name, "parent")) { if (relativeNode == nullptr) return; node = relativeNode->parent; } else if (Q_streq(name, "root")) { if (relativeNode == nullptr) return; node = relativeNode->root; } else if (Q_streq(name, "child")) { if (iterationNode == nullptr) return; node = const_cast<uiNode_t *>(iterationNode); } else node = UI_GetWindow(name); break; case '.': /* child node */ if (Q_streq(name, "parent")) childnode = node->parent; else if (Q_streq(name, "root")) childnode = node->root; else { childnode = UI_GetNode(node, name); /* if no node found and if we need it, then it is possible we call a lua based function */ if (luaMethod && !childnode) { *resultProperty = UI_GetPropertyOrLuaMethod(node, name, luaMethod); if (luaMethod->type) { childnode = node; } } } node = childnode; break; case '#': /* window index */ /** @todo FIXME use a warning instead of an assert */ assert(UI_Node_IsWindow(node)); node = UI_WindowNodeGetIndexedChild(node, name); break; case '@': /* property */ assert(nextCommand == '\0'); *resultProperty = UI_GetPropertyOrLuaMethod(node, name, luaMethod); *resultNode = node; return; } if (!node) return; } *resultNode = node; return; }