/** * @brief Return the first visible node at a position * @param[in] node Node where we must search * @param[in] rx Relative x position to the parent of the node * @param[in] ry Relative y position to the parent of the node * @return The first visible node at position, else NULL */ static uiNode_t *UI_GetNodeInTreeAtPosition (uiNode_t *node, int rx, int ry) { uiNode_t *find; if (node->invis || node->behaviour->isVirtual || !UI_CheckVisibility(node)) return NULL; /* relative to the node */ rx -= node->pos[0]; ry -= node->pos[1]; /* check bounding box */ if (rx < 0 || ry < 0 || rx >= node->size[0] || ry >= node->size[1]) return NULL; /** @todo we should improve the loop (last-to-first) */ find = NULL; if (node->firstChild) { uiNode_t *child; vec2_t clientPosition = {0, 0}; if (node->behaviour->getClientPosition) node->behaviour->getClientPosition(node, clientPosition); rx -= clientPosition[0]; ry -= clientPosition[1]; for (child = node->firstChild; child; child = child->next) { uiNode_t *tmp; tmp = UI_GetNodeInTreeAtPosition(child, rx, ry); if (tmp) find = tmp; } rx += clientPosition[0]; ry += clientPosition[1]; } if (find) return find; /* disable ghost/excluderect in debug mode 2 */ if (UI_DebugMode() != 2) { int i; /* is the node tangible */ if (node->ghost) return NULL; /* check excluded box */ for (i = 0; i < node->excludeRectNum; i++) { if (rx >= node->excludeRect[i].pos[0] && rx < node->excludeRect[i].pos[0] + node->excludeRect[i].size[0] && ry >= node->excludeRect[i].pos[1] && ry < node->excludeRect[i].pos[1] + node->excludeRect[i].size[1]) return NULL; } } /* we are over the node */ return node; }
/** * @brief Return the first visible node at a position * @param[in] node Node where we must search * @param[in] rx Relative x position to the parent of the node * @param[in] ry Relative y position to the parent of the node * @return The first visible node at position, else nullptr */ static uiNode_t *UI_GetNodeInTreeAtPosition (uiNode_t *node, int rx, int ry) { uiNode_t *find; if (node->invis || UI_Node_IsVirtual(node) || !UI_CheckVisibility(node)) return nullptr; /* relative to the node */ rx -= node->box.pos[0]; ry -= node->box.pos[1]; /* check bounding box */ if (rx < 0 || ry < 0 || rx >= node->box.size[0] || ry >= node->box.size[1]) return nullptr; /** @todo we should improve the loop (last-to-first) */ find = nullptr; if (node->firstChild) { uiNode_t *child; vec2_t clientPosition = {0, 0}; if (UI_Node_IsScrollableContainer(node)) UI_Node_GetClientPosition(node, clientPosition); rx -= clientPosition[0]; ry -= clientPosition[1]; for (child = node->firstChild; child; child = child->next) { uiNode_t *tmp; tmp = UI_GetNodeInTreeAtPosition(child, rx, ry); if (tmp) find = tmp; } rx += clientPosition[0]; ry += clientPosition[1]; } if (find) return find; /* disable ghost/excluderect in debug mode 2 */ if (UI_DebugMode() != 2) { uiExcludeRect_t *excludeRect; /* is the node tangible */ if (node->ghost) return nullptr; /* check excluded box */ for (excludeRect = node->firstExcludeRect; excludeRect != nullptr; excludeRect = excludeRect->next) { if (rx >= excludeRect->pos[0] && rx < excludeRect->pos[0] + excludeRect->size[0] && ry >= excludeRect->pos[1] && ry < excludeRect->pos[1] + excludeRect->size[1]) return nullptr; } } /* we are over the node */ return node; }
/** * @sa UI_FocusExecuteActionNode * @note node must be in a window */ static uiNode_t* UI_GetNextActionNode (uiNode_t* node) { if (node) node = node->next; while (node) { if (UI_CheckVisibility(node) && !node->invis && ((node->onClick && node->onMouseEnter) || node->onMouseEnter)) return node; node = node->next; } return nullptr; }
/** * @brief Call mouse move only if the mouse position change */ bool UI_CheckMouseMove (void) { /* is hovered node no more draw */ if (hoveredNode && (hoveredNode->invis || !UI_CheckVisibility(hoveredNode))) UI_InvalidateMouse(); if (mousePosX != oldMousePosX || mousePosY != oldMousePosY) { oldMousePosX = mousePosX; oldMousePosY = mousePosY; UI_MouseMove(mousePosX, mousePosY); return true; } return false; }
/** * @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(); }