/** * @brief Clone a node * @param[in] node Node to clone * @param[in] recursive True if we also must clone subnodes * @param[in] newWindow Window where the nodes must be add (this function only link node into window, not window into the new node) * @param[in] newName New node name, else nullptr to use the source name * @param[in] isDynamic Allocate a node in static or dynamic memory * @todo exclude rect is not safe cloned. * @todo actions are not cloned. It is be a problem if we use add/remove listener into a cloned node. */ uiNode_t* UI_CloneNode (const uiNode_t* node, uiNode_t* newWindow, bool recursive, const char* newName, bool isDynamic) { uiNode_t* newNode = UI_AllocNodeWithoutNew(nullptr, UI_Node_GetWidgetName(node), isDynamic); /* clone all data */ memcpy(newNode, node, UI_Node_GetMemorySize(node)); newNode->dynamic = isDynamic; /* custom name */ if (newName != nullptr) { Q_strncpyz(newNode->name, newName, sizeof(newNode->name)); if (strlen(newNode->name) != strlen(newName)) Com_Printf("UI_CloneNode: Node name \"%s\" truncated. New name is \"%s\"\n", newName, newNode->name); } /* clean up node navigation */ if (node->root == node && newWindow == nullptr) newWindow = newNode; newNode->root = newWindow; newNode->parent = nullptr; newNode->firstChild = nullptr; newNode->lastChild = nullptr; newNode->next = nullptr; newNode->super = node; /* clone node methods */ if (node->nodeMethods) { newNode->nodeMethods = HASH_CloneTable(node->nodeMethods); } /* allocate memories */ if (newNode->dynamic) { UI_Node_InitNodeDynamic(newNode); } /* typically, cloning makes a copy of all the internals of a source node; override the ::clone(node) method to alter this behaviour */ UI_Node_Clone(node, newNode); /* clone child */ if (recursive) { for (uiNode_t* childNode = node->firstChild; childNode; childNode = childNode->next) { uiNode_t* newChildNode = UI_CloneNode(childNode, newWindow, recursive, nullptr, isDynamic); UI_AppendNode(newNode, newChildNode); } } return newNode; }
/** * @brief Clone a node * @param[in] node Node to clone * @param[in] recursive True if we also must clone subnodes * @param[in] newWindow Window where the nodes must be add (this function only link node into window, not window into the new node) * @param[in] newName New node name, else nullptr to use the source name * @param[in] isDynamic Allocate a node in static or dynamic memory * @todo exclude rect is not safe cloned. * @todo actions are not cloned. It is be a problem if we use add/remove listener into a cloned node. */ uiNode_t* UI_CloneNode (const uiNode_t* node, uiNode_t *newWindow, bool recursive, const char *newName, bool isDynamic) { uiNode_t* newNode = UI_AllocNodeWithoutNew(nullptr, UI_Node_GetWidgetName(node), isDynamic); /* clone all data */ memcpy(newNode, node, UI_Node_GetMemorySize(node)); newNode->dynamic = isDynamic; /* custom name */ if (newName != nullptr) { Q_strncpyz(newNode->name, newName, sizeof(newNode->name)); if (strlen(newNode->name) != strlen(newName)) Com_Printf("UI_CloneNode: Node name \"%s\" truncated. New name is \"%s\"\n", newName, newNode->name); } /* clean up node navigation */ if (node->root == node && newWindow == nullptr) newWindow = newNode; newNode->root = newWindow; newNode->parent = nullptr; newNode->firstChild = nullptr; newNode->lastChild = nullptr; newNode->next = nullptr; newNode->super = node; /* clone child */ if (recursive) { uiNode_t* childNode; for (childNode = node->firstChild; childNode; childNode = childNode->next) { uiNode_t* newChildNode = UI_CloneNode(childNode, newWindow, recursive, nullptr, isDynamic); UI_AppendNode(newNode, newChildNode); } } /* allocate memories */ if (newNode->dynamic) UI_Node_NewNode(newNode); UI_Node_Clone(node, newNode); return newNode; }