/** * @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; }
/** * @brief Replace injection identifiers (e.g. <eventParam>) by a value * @note The injection identifier can be every node value - e.g. <image> or <width>. * It's also possible to do something like * @code * cmd "set someCvar <min>/<max>" * @endcode */ const char* UI_GenInjectedString (const char* input, qboolean addNewLine, const uiCallContext_t *context) { static char cmd[256]; int length = sizeof(cmd) - (addNewLine ? 2 : 1); static char propertyName[MAX_VAR]; const char *cin = input; char *cout = cmd; while (length && cin[0] != '\0') { if (cin[0] == '<') { /* read propertyName between '<' and '>' */ const char *next = UI_GenCommandReadProperty(cin, propertyName, sizeof(propertyName)); if (next) { /* cvar injection */ if (Q_strstart(propertyName, "cvar:")) { const cvar_t *cvar = Cvar_Get(propertyName + 5, "", 0, NULL); const int l = snprintf(cout, length, "%s", cvar->string); cout += l; cin = next; length -= l; continue; } else if (Q_strstart(propertyName, "node:")) { const char *path = propertyName + 5; uiNode_t *node; const value_t *property; const char* string; int l; UI_ReadNodePath(path, context->source, &node, &property); if (!node) { Com_Printf("UI_GenInjectedString: Node '%s' wasn't found; '' returned\n", path); #ifdef DEBUG Com_Printf("UI_GenInjectedString: Path relative to '%s'\n", UI_GetPath(context->source)); #endif string = ""; } else if (!property) { Com_Printf("UI_GenInjectedString: Property '%s' wasn't found; '' returned\n", path); string = ""; } else { string = UI_GetStringFromNodeProperty(node, property); if (string == NULL) { Com_Printf("UI_GenInjectedString: String getter for '%s' property do not exists; '' injected\n", path); string = ""; } } l = snprintf(cout, length, "%s", string); cout += l; cin = next; length -= l; continue; /* source path injection */ } else if (Q_strstart(propertyName, "path:")) { if (context->source) { const char *command = propertyName + 5; const uiNode_t *node = NULL; if (Q_streq(command, "root")) node = context->source->root; else if (Q_streq(command, "this")) node = context->source; else if (Q_streq(command, "parent")) node = context->source->parent; else Com_Printf("UI_GenCommand: Command '%s' for path injection unknown\n", command); if (node) { const int l = snprintf(cout, length, "%s", UI_GetPath(node)); cout += l; cin = next; length -= l; continue; } } /* no prefix */ } else { /* source property injection */ if (context->source) { /* find property definition */ const value_t *property = UI_GetPropertyFromBehaviour(context->source->behaviour, propertyName); if (property) { const char* value; int l; /* inject the property value */ value = UI_GetStringFromNodeProperty(context->source, property); if (value == NULL) value = ""; l = snprintf(cout, length, "%s", value); cout += l; cin = next; length -= l; continue; } } /* param injection */ if (UI_GetParamNumber(context) != 0) { int arg; const int checked = sscanf(propertyName, "%d", &arg); if (checked == 1 && arg >= 1 && arg <= UI_GetParamNumber(context)) { const int l = snprintf(cout, length, "%s", UI_GetParam(context, arg)); cout += l; cin = next; length -= l; continue; } } } } } *cout++ = *cin++; length--; } /* is buffer too small? */ assert(cin[0] == '\0'); if (addNewLine) *cout++ = '\n'; *cout++ = '\0'; /* copy the result into a free va slot */ return va("%s", cmd); }