/** * @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; }
/** * @brief Update an absolute position to a relative one * @param[in] node Context node * @param[in,out] x an absolute x position * @param[in,out] y an absolute y position */ void UI_NodeAbsoluteToRelativePos (const uiNode_t* node, int* x, int* y) { assert(node != nullptr); /* if we request the position of an undrawable node, there is a problem */ assert(node->behaviour->isVirtual == false); assert(x != nullptr); assert(y != nullptr); /* if we request the position of an undrawable node, there is a problem */ if (node->behaviour->isVirtual) Com_Error(ERR_DROP, "UI_NodeAbsoluteToRelativePos: Node '%s' doesn't have a position", node->name); while (node) { *x -= node->box.pos[0]; *y -= node->box.pos[1]; if (UI_Node_IsScrollableContainer(node)) { vec2_t clientPosition = {0, 0}; UI_Node_GetClientPosition(node, clientPosition); *x -= clientPosition[0]; *y -= clientPosition[1]; } node = node->parent; } }
/** * @brief Returns the absolute position of a node in the screen. * Screen position is not used for the node rendering cause we use OpenGL * translations. But this function is need for some R_functions methodes. * @param[in] node Context node * @param[out] pos Absolute position into the screen */ void UI_GetNodeScreenPos (const uiNode_t* node, vec2_t pos) { assert(node); assert(pos); /* if we request the position of a non drawable node, there is a problem */ if (node->behaviour->isVirtual) Com_Error(ERR_FATAL, "UI_GetNodeAbsPos: Node '%s' doesn't have a position", node->name); Vector2Set(pos, 0, 0); while (node) { #ifdef DEBUG if (node->box.pos[0] != (int)node->box.pos[0] || node->box.pos[1] != (int)node->box.pos[1]) Com_Error(ERR_FATAL, "UI_GetNodeAbsPos: Node '%s' position %f,%f is not integer", UI_GetPath(node), node->box.pos[0], node->box.pos[1]); #endif pos[0] += node->box.pos[0]; pos[1] += node->box.pos[1]; node = node->parent; if (node && UI_Node_IsScrollableContainer(node)) { vec2_t clientPosition = {0, 0}; UI_Node_GetClientPosition(node, clientPosition); pos[0] += clientPosition[0]; pos[1] += clientPosition[1]; } } }
/** * @brief return true if the node size change and update the cache */ bool uiAbstractScrollableNode::isSizeChange (uiNode_t *node) { assert(UI_Node_IsScrollableContainer(node)); if (!Vector2Equal(node->box.size, EXTRADATA(node).cacheSize)) { Vector2Copy(node->box.size, EXTRADATA(node).cacheSize); return true; } return false; }
/** * @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 */ bool uiAbstractScrollableNode::setScrollY (uiNode_t *node, int viewPos, int viewSize, int fullSize) { bool updated; assert(UI_Node_IsScrollableContainer(node)); updated = EXTRADATA(node).scrollY.set(viewPos, viewSize, fullSize); if (updated && EXTRADATA(node).onViewChange) UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange); return updated; }
/** * @brief Scroll the Y scroll with a relative position, and call event if need * @return true, if something have change */ bool uiAbstractScrollableNode::scrollY (uiNode_t *node, int offset) { assert(UI_Node_IsScrollableContainer(node)); return setScrollY(node, EXTRADATA(node).scrollY.viewPos + offset, -1, -1); }