/** * @brief Register a property to a behaviour. * It should not be used in the code * @param behaviour Target behaviour * @param name Name of the property * @param type Type of the property * @param pos position of the attribute (which store property memory) into the node structure * @param size size of the attribute (which store property memory) into the node structure * @see UI_RegisterNodeProperty * @see UI_RegisterExtradataNodeProperty * @return A link to the node property */ const struct value_s *UI_RegisterNodePropertyPosSize_ (struct uiBehaviour_s *behaviour, const char* name, int type, size_t pos, size_t size) { value_t *property = UI_AllocHunkMemory(sizeof(value_t), STRUCT_MEMORY_ALIGN, qfalse); if (property == NULL) Com_Error(ERR_FATAL, "UI_RegisterNodePropertyPosSize_: UI memory hunk exceeded - increase the size"); if (type == V_STRING || type == V_LONGSTRING || type == V_CVAR_OR_LONGSTRING || V_CVAR_OR_STRING) { size = 0; } property->string = name; property->type = type; property->ofs = pos; property->size = size; if (behaviour->localProperties == NULL) { /* temporary memory allocation */ behaviour->localProperties = (const value_t **)Mem_PoolAlloc(sizeof(*behaviour->localProperties) * LOCAL_PROPERTY_SIZE, ui_sysPool, 0); } if (behaviour->propertyCount >= LOCAL_PROPERTY_SIZE-1) { Com_Error(ERR_FATAL, "UI_RegisterNodePropertyPosSize_: Property memory of behaviour %s is full.", behaviour->name); } behaviour->localProperties[behaviour->propertyCount++] = property; behaviour->localProperties[behaviour->propertyCount] = NULL; return property; }
/** * @brief Allocate a color into the UI static memory * @note Its not a dynamic memory allocation. Please only use it at the loading time * @param[in] count number of element need to allocate * @todo Assert out when we are not in parsing/loading stage */ vec4_t* UI_AllocStaticColor (int count) { vec4_t* result; assert(count > 0); result = (vec4_t*) UI_AllocHunkMemory(sizeof(vec_t) * 4 * count, sizeof(vec_t), false); if (result == nullptr) Com_Error(ERR_FATAL, "UI_AllocColor: UI memory hunk exceeded - increase the size"); return result; }
/** * @brief Allocate a float into the UI static memory * @note Its not a dynamic memory allocation. Please only use it at the loading time * @param[in] count number of element need to allocate * @todo Assert out when we are not in parsing/loading stage */ float* UI_AllocStaticFloat (int count) { float* result; assert(count > 0); result = (float*) UI_AllocHunkMemory(sizeof(float) * count, sizeof(float), false); if (result == nullptr) Com_Error(ERR_FATAL, "UI_AllocFloat: UI memory hunk exceeded - increase the size"); return result; }
/** * @brief Allocate a string into the UI static memory * @note Its not a dynamic memory allocation. Please only use it at the loading time * @param[in] string Use to initialize the string * @param[in] size request a fixed memory size, if 0 the string size is used * @todo Assert out when we are not in parsing/loading stage */ char* UI_AllocStaticString (const char* string, int size) { char* result; if (size == 0) { size = strlen(string) + 1; } result = (char*) UI_AllocHunkMemory(size, sizeof(char), false); if (result == nullptr) Com_Error(ERR_FATAL, "UI_AllocString: UI memory hunk exceeded - increase the size"); Q_strncpyz(result, string, size); return result; }
static bool UI_ParseExcludeRect (uiNode_t* node, const char** text, const char** token, const char* errhead) { uiExcludeRect_t rect; uiExcludeRect_t* newRect; /* get parameters */ *token = Com_EParse(text, errhead, node->name); if (!*text) return false; if ((*token)[0] != '{') { Com_Printf("UI_ParseExcludeRect: node with bad excluderect ignored (node \"%s\")\n", UI_GetPath(node)); return true; } do { *token = Com_EParse(text, errhead, node->name); if (!*text) return false; /** @todo move it into a property array */ if (Q_streq(*token, "pos")) { *token = Com_EParse(text, errhead, node->name); if (!*text) return false; Com_EParseValue(&rect, *token, V_POS, offsetof(uiExcludeRect_t, pos), sizeof(vec2_t)); } else if (Q_streq(*token, "size")) { *token = Com_EParse(text, errhead, node->name); if (!*text) return false; Com_EParseValue(&rect, *token, V_POS, offsetof(uiExcludeRect_t, size), sizeof(vec2_t)); } } while ((*token)[0] != '}'); newRect = (uiExcludeRect_t*) UI_AllocHunkMemory(sizeof(*newRect), STRUCT_MEMORY_ALIGN, false); if (newRect == nullptr) { Com_Printf("UI_ParseExcludeRect: ui hunk memory exceeded."); return false; } /* move data to final memory and link to node */ *newRect = rect; newRect->next = node->firstExcludeRect; node->firstExcludeRect = newRect; return true; }
/** * @brief Register a property to a behaviour. * It should not be used in the code * @param behaviour Target behaviour * @param name Name of the property * @param type Type of the property * @param pos position of the attribute (which store property memory) into the node structure * @param size size of the attribute (which store property memory) into the node structure * @see UI_RegisterNodeProperty * @see UI_RegisterExtradataNodeProperty * @return A link to the node property */ const struct value_s *UI_RegisterNodePropertyPosSize_ (uiBehaviour_t *behaviour, const char* name, int type, size_t pos, size_t size) { value_t *property = (value_t*) UI_AllocHunkMemory(sizeof(value_t), STRUCT_MEMORY_ALIGN, false); if (property == NULL) Com_Error(ERR_FATAL, "UI_RegisterNodePropertyPosSize_: UI memory hunk exceeded - increase the size"); if (type == V_STRING || type == V_LONGSTRING || type == V_CVAR_OR_LONGSTRING || V_CVAR_OR_STRING) { size = 0; } property->string = name; property->type = (valueTypes_t) type; property->ofs = pos; property->size = size; if (behaviour->localProperties == NULL) { /* temporary memory allocation */ behaviour->localProperties = Mem_PoolAllocTypeN(value_t const*, LOCAL_PROPERTY_SIZE, ui_sysPool); }
/** * @brief Allocate a node into the UI memory (do not call behaviour->new) * @note It's not a dynamic memory allocation. Please only use it at the loading time * @todo Assert out when we are not in parsing/loading stage * @param[in] name Name of the new node, else nullptr if we don't want to edit it. * @param[in] type Name of the node behavior * @param[in] isDynamic Allocate a node in static or dynamic memory */ static uiNode_t* UI_AllocNodeWithoutNew (const char* name, const char* type, bool isDynamic) { uiNode_t* node; uiBehaviour_t *behaviour; int nodeSize; behaviour = UI_GetNodeBehaviour(type); if (behaviour == nullptr) Com_Error(ERR_FATAL, "UI_AllocNodeWithoutNew: Node behaviour '%s' doesn't exist", type); nodeSize = sizeof(*node) + behaviour->extraDataSize; if (!isDynamic) { void *memory = UI_AllocHunkMemory(nodeSize, STRUCT_MEMORY_ALIGN, true); if (memory == nullptr) Com_Error(ERR_FATAL, "UI_AllocNodeWithoutNew: No more memory to allocate a new node - increase the cvar ui_hunksize"); node = static_cast<uiNode_t*>(memory); ui_global.numNodes++; } else { node = static_cast<uiNode_t*>(Mem_PoolAlloc(nodeSize, ui_dynPool, 0)); node->dynamic = true; } node->behaviour = behaviour; #ifdef DEBUG UI_Node_DebugCountWidget(node, 1); #endif if (UI_Node_IsAbstract(node)) Com_Error(ERR_FATAL, "UI_AllocNodeWithoutNew: Node behavior '%s' is abstract. We can't instantiate it.", type); if (name != nullptr) { Q_strncpyz(node->name, name, sizeof(node->name)); if (strlen(node->name) != strlen(name)) Com_Printf("UI_AllocNodeWithoutNew: Node name \"%s\" truncated. New name is \"%s\"\n", name, node->name); } /* initialize default properties */ UI_Node_Loading(node); return node; }
/** * @brief Initialize a node behaviour memory, after registration, and before unsing it. * @param behaviour Behaviour to initialize */ void UI_InitializeNodeBehaviour (uiBehaviour_t* behaviour) { if (behaviour->isInitialized) return; /* everything inherits 'abstractnode' */ if (behaviour->extends == NULL && !Q_streq(behaviour->name, "abstractnode")) { behaviour->extends = "abstractnode"; } if (behaviour->extends) { int i = 0; /** TODO Find a way to remove that, if possible */ behaviour->super = UI_GetNodeBehaviour(behaviour->extends); UI_InitializeNodeBehaviour(behaviour->super); while (qtrue) { const size_t pos = virtualFunctions[i]; uintptr_t superFunc; uintptr_t func; if (pos == -1) break; /* cache super function if we don't overwrite it */ superFunc = *(uintptr_t*)((byte*)behaviour->super + pos); func = *(uintptr_t*)((byte*)behaviour + pos); if (func == 0 && superFunc != 0) *(uintptr_t*)((byte*)behaviour + pos) = superFunc; i++; } } /* sort properties by alphabet */ if (behaviour->localProperties) { int i = 0; const value_t* previous; const value_t** oldmemory = behaviour->localProperties; behaviour->localProperties = UI_AllocHunkMemory(sizeof(value_t*) * (behaviour->propertyCount+1), STRUCT_MEMORY_ALIGN, qfalse); if (behaviour->localProperties == NULL) { Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: UI memory hunk exceeded - increase the size"); } previous = NULL; for (i = 0; i < behaviour->propertyCount; i++) { const value_t* better = NULL; const value_t** current; /* search the next element after previous */ for (current = oldmemory; *current != NULL; current++) { if (previous != NULL && Q_strcasecmp(previous->string, (*current)->string) >= 0) { continue; } if (better == NULL || Q_strcasecmp(better->string, (*current)->string) >= 0) { better = *current; } } previous = better; behaviour->localProperties[i] = better; } behaviour->localProperties[behaviour->propertyCount] = NULL; Mem_Free(oldmemory); } /* property must not overwrite another property */ if (behaviour->super && behaviour->localProperties) { const value_t** property = behaviour->localProperties; while (*property) { const value_t *p = UI_GetPropertyFromBehaviour(behaviour->super, (*property)->string); #if 0 /**< @todo not possible at the moment, not sure its the right way */ const uiBehaviour_t *b = UI_GetNodeBehaviour(current->string); #endif if (p != NULL) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' overwrite another property", (*property)->string, behaviour->name); #if 0 /**< @todo not possible at the moment, not sure its the right way */ if (b != NULL) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' use the name of an existing node behaviour", (*property)->string, behaviour->name); #endif property++; } } /* Sanity: A property must not be outside the node memory */ if (behaviour->localProperties) { const int size = sizeof(uiNode_t) + behaviour->extraDataSize; const value_t** property = behaviour->localProperties; while (*property) { if ((*property)->type != V_UI_NODEMETHOD && (*property)->ofs + (*property)->size > size) Com_Error(ERR_FATAL, "UI_InitializeNodeBehaviour: property '%s' from node behaviour '%s' is outside the node memory. The C code need a fix.", (*property)->string, behaviour->name); property++; } } behaviour->isInitialized = qtrue; }