/** * @brief Callback to execute a confunc */ static void UI_ConfuncCommand_f (void) { uiNode_t *node = (uiNode_t *) Cmd_Userdata(); assert(node); assert(UI_NodeInstanceOf(node, "confunc")); UI_ExecuteConFuncActions(node, node->onClick); }
/** * @brief Get the line number under an absolute position * @param[in] node a text node * @param[in] x,y position on the screen * @return The line number under the position (0 = first line) */ static int UI_TextNodeGetLine (const uiNode_t* node, int x, int y) { int lineHeight; int line; assert(UI_NodeInstanceOf(node, "text")); lineHeight = EXTRADATACONST(node).lineHeight; if (lineHeight == 0) { const char* font = UI_GetFontFromNode(node); lineHeight = UI_FontGetHeight(font); } UI_NodeAbsoluteToRelativePos(node, &x, &y); y -= node->padding; /* skip position over the first line */ if (y < 0) return -1; line = (int) (y / lineHeight) + EXTRADATACONST(node).super.scrollY.viewPos; /* skip position under the last line */ if (line >= EXTRADATACONST(node).super.scrollY.fullSize) return -1; return line; }
/** * @brief Checks whether the given node is a virtual confunc that can be overridden from inheriting nodes. * @param node The node to check (must be a confunc node). * @return @c true if the given node is a dummy node, @c false otherwise. */ static qboolean UI_ConFuncIsVirtual (const uiNode_t *const node) { /* magic way to know if it is a dummy node (used for inherited confunc) */ const uiNode_t *dummy = (const uiNode_t*) Cmd_GetUserdata(node->name); assert(node); assert(UI_NodeInstanceOf(node, "confunc")); return (dummy != NULL && dummy->parent == NULL); }
/** * @brief Checks whether the given node is a virtual confunc that can be overridden from inheriting nodes. * @param node The node to check (must be a confunc node). * @return @c true if the given node is a dummy node, @c false otherwise. */ static bool UI_ConFuncIsVirtual (const uiNode_t* const node) { /* magic way to know if it is a dummy node (used for inherited confunc) */ const uiNode_t* dummy = static_cast<const uiNode_t*>(Cmd_GetUserdata(node->name)); assert(node); assert(UI_NodeInstanceOf(node, "confunc")); return (dummy != nullptr && dummy->parent == nullptr); }
/** * @brief return true if the node size change and update the cache */ qboolean UI_AbstractScrollableNodeIsSizeChange (uiNode_t *node) { assert(UI_NodeInstanceOf(node, "abstractscrollable")); if (!Vector2Equal(node->size, EXTRADATA(node).cacheSize)) { Vector2Copy(node->size, EXTRADATA(node).cacheSize); return qtrue; } return qfalse; }
/** * @brief Search a a key binding from a window node. * Window node store key bindings for his node child. * @param node A window node * @param key A key code, either K_ value or lowercase ascii */ uiKeyBinding_t* UI_WindowNodeGetKeyBinding (uiNode_t const* const node, unsigned int key) { uiKeyBinding_t* binding = EXTRADATACONST(node).keyList; assert(UI_NodeInstanceOf(node, "window")); while (binding) { if (binding->key == key) break; binding = binding->next; } return binding; }
/** * @brief Set the Y scroll to a position, and call event if need * @param[in] node Context node * @param[in] viewPos New position to set, else -1 if no change * @param[in] viewSize New view size to set, else -1 if no change * @param[in] fullSize New full size to set, else -1 if no change * @return True, if something have change */ qboolean UI_AbstractScrollableNodeSetY (uiNode_t *node, int viewPos, int viewSize, int fullSize) { qboolean updated; assert(UI_NodeInstanceOf(node, "abstractscrollable")); updated = UI_SetScroll(&EXTRADATA(node).scrollY, viewPos, viewSize, fullSize); if (updated && EXTRADATA(node).onViewChange) UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange); return updated; }
/** * @brief Callback to execute a confunc */ static void UI_ConfuncCommand_f (void) { uiNode_t* node = static_cast<uiNode_t*>(Cmd_Userdata()); assert(node); assert(UI_NodeInstanceOf(node, "confunc")); if (node->onClick != nullptr) { UI_ExecuteConFuncActions(node, node->onClick); } if (node->lua_onClick != LUA_NOREF) { UI_ExecuteLuaConFunc (node, node->lua_onClick); } }
/** * @brief Scroll to the bottom * @param[in] nodePath absolute path */ void UI_TextScrollEnd (const char* nodePath) { uiNode_t* node = UI_GetNodeByPath(nodePath); if (!node) { Com_DPrintf(DEBUG_CLIENT, "UI_TextScrollEnd: Node '%s' could not be found\n", nodePath); return; } if (!UI_NodeInstanceOf(node, "text")) { Com_Printf("UI_TextScrollEnd: '%s' node is no instance of 'text'.\n", Cmd_Argv(1)); return; } uiTextNode* b = dynamic_cast<uiTextNode*>(node->behaviour->manager.get()); b->validateCache(node); if (EXTRADATA(node).super.scrollY.fullSize > EXTRADATA(node).super.scrollY.viewSize) { EXTRADATA(node).super.scrollY.viewPos = EXTRADATA(node).super.scrollY.fullSize - EXTRADATA(node).super.scrollY.viewSize; UI_ExecuteEventActions(node, EXTRADATA(node).super.onViewChange); } }
/** * @brief Active an element of a vscrollbarnode. * @note This command work like an user, so, if need, change event are fired */ static void UI_ActiveVScrollbarNode_f () { uiNode_t *node; int actionId; if (Cmd_Argc() != 3) { Com_Printf("Usage: %s <node-path> <action-id>\n", Cmd_Argv(0)); return; } node = UI_GetNodeByPath(Cmd_Argv(1)); if (node == NULL) { Com_Printf("UI_ActiveVScrollbarNode_f: node '%s' not found\n", Cmd_Argv(1)); return; } if (!UI_NodeInstanceOf(node, "vscrollbar")) { Com_Printf("UI_ActiveVScrollbarNode_f: node '%s' is not a 'vscrollbar'\n", Cmd_Argv(1)); return; } actionId = atoi(Cmd_Argv(2)); UI_VScrollbarNodeAction(node, actionId, qfalse); }
/** * @brief Add a key binding to a window node. * Window node store key bindings for his node child. * @param node A window node * @param binding Key binding to link with the window (structure should not be already linked somewhere) * @todo Rework that function to remove possible wrong use of that function */ void UI_WindowNodeRegisterKeyBinding (uiNode_t* node, uiKeyBinding_t* binding) { assert(UI_NodeInstanceOf(node, "window")); binding->next = EXTRADATA(node).keyList; EXTRADATA(node).keyList = binding; }
/** * @brief Check if a window is fullscreen or not */ bool UI_WindowIsFullScreen (const uiNode_t* const node) { assert(UI_NodeInstanceOf(node, "window")); return EXTRADATACONST(node).isFullScreen; }
/** * @brief Scroll the Y scroll with a relative position, and call event if need * @return True, if something have change */ qboolean UI_AbstractScrollableNodeScrollY (uiNode_t *node, int offset) { assert(UI_NodeInstanceOf(node, "abstractscrollable")); return UI_AbstractScrollableNodeSetY(node, EXTRADATA(node).scrollY.viewPos + offset, -1, -1); }
/** * @todo need to merge UI model case, and the common case (looks to be a copy-pasted code) */ void UI_DrawModelNode (uiNode_t* node, const char* source) { modelInfo_t mi; uiModel_t* model; vec3_t nodeorigin; vec2_t screenPos; assert(UI_NodeInstanceOf(node, "model")); /**< We use model extradata */ if (!source || source[0] == '\0') return; model = UI_GetUIModel(source); /* direct model name - no UI model definition */ if (!model) { /* prevent the searching for a model def in the next frame */ mi.model = R_FindModel(source); mi.name = source; if (!mi.model) { Com_Printf("Could not find model '%s'\n", source); return; } } /* compute the absolute origin ('origin' property is relative to the node center) */ UI_GetNodeScreenPos(node, screenPos); UI_GetNodeAbsPos(node, nodeorigin); R_CleanupDepthBuffer(nodeorigin[0], nodeorigin[1], node->box.size[0], node->box.size[1]); if (EXTRADATA(node).clipOverflow) { UI_PushClipRect(screenPos[0], screenPos[1], node->box.size[0], node->box.size[1]); } nodeorigin[0] += node->box.size[0] / 2 + EXTRADATA(node).origin[0]; nodeorigin[1] += node->box.size[1] / 2 + EXTRADATA(node).origin[1]; nodeorigin[2] = EXTRADATA(node).origin[2]; VectorMA(EXTRADATA(node).angles, cls.frametime, EXTRADATA(node).omega, EXTRADATA(node).angles); mi.origin = nodeorigin; mi.angles = EXTRADATA(node).angles; mi.scale = EXTRADATA(node).scale; mi.center = nullVector; mi.color = node->color; mi.mesh = 0; /* special case to draw models with UI model */ if (model) { UI_DrawModelNodeWithUIModel(node, source, &mi, model); if (EXTRADATA(node).clipOverflow) UI_PopClipRect(); return; } /* if the node is linked to a parent, the parent will display it */ if (EXTRADATA(node).tag) { if (EXTRADATA(node).clipOverflow) UI_PopClipRect(); return; } /* autoscale? */ if (EXTRADATA(node).autoscale) { vec3_t autoScale; vec3_t autoCenter; const vec2_t size = {node->box.size[0] - node->padding, node->box.size[1] - node->padding}; R_ModelAutoScale(size, &mi, autoScale, autoCenter); } /* no animation */ mi.frame = 0; mi.oldframe = 0; mi.backlerp = 0; /* get skin */ if (EXTRADATA(node).skin && *EXTRADATA(node).skin) mi.skin = atoi(UI_GetReferenceString(node, EXTRADATA(node).skin)); else mi.skin = 0; /* do animations */ if (EXTRADATA(node).animation && *EXTRADATA(node).animation) { const char* ref; ref = UI_GetReferenceString(node, EXTRADATA(node).animation); /* check whether the cvar value changed */ if (strncmp(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE)) { Q_strncpyz(EXTRADATA(node).oldRefValue, source, MAX_OLDREFVALUE); /* model has changed but mem is already reserved in pool */ Mem_Free(EXTRADATA(node).animationState); EXTRADATA(node).animationState = nullptr; } animState_t* as = EXTRADATA(node).animationState; if (!as) { as = Mem_PoolAllocType(animState_t, cl_genericPool); if (!as) Com_Error(ERR_DROP, "Model %s should have animState_t for animation %s - but doesn't\n", mi.name, ref); R_AnimChange(as, mi.model, ref); EXTRADATA(node).animationState = as; } else { const char* anim; /* change anim if needed */ anim = R_AnimGetName(as, mi.model); if (anim && !Q_streq(anim, ref)) R_AnimChange(as, mi.model, ref); R_AnimRun(as, mi.model, cls.frametime * 1000); } mi.frame = as->frame; mi.oldframe = as->oldframe; mi.backlerp = as->backlerp; } /* draw the main model on the node */ R_DrawModelDirect(&mi, nullptr, nullptr); /* draw all children */ if (node->firstChild) { uiNode_t* child; modelInfo_t pmi = mi; for (child = node->firstChild; child; child = child->next) { const char* tag; char childSource[MAX_VAR]; const char* childRef; /* skip non "model" nodes */ if (child->behaviour != node->behaviour) continue; /* skip invisible child */ if (child->invis || !UI_CheckVisibility(child)) continue; OBJZERO(mi); mi.angles = EXTRADATA(child).angles; mi.scale = EXTRADATA(child).scale; mi.center = nullVector; mi.origin = EXTRADATA(child).origin; mi.color = pmi.color; /* get the anchor name to link the model into the parent */ tag = EXTRADATA(child).tag; /* init model name */ childRef = UI_GetReferenceString(child, EXTRADATA(child).model); if (Q_strnull(childRef)) childSource[0] = '\0'; else Q_strncpyz(childSource, childRef, sizeof(childSource)); mi.model = R_FindModel(childSource); mi.name = childSource; /* init skin */ if (EXTRADATA(child).skin && *EXTRADATA(child).skin) mi.skin = atoi(UI_GetReferenceString(child, EXTRADATA(child).skin)); else mi.skin = 0; R_DrawModelDirect(&mi, &pmi, tag); } } if (EXTRADATA(node).clipOverflow) UI_PopClipRect(); }