static void UI_AbstractNodeCallCreateChild (uiNode_t* node, const uiCallContext_t* context) { uiNode_t* child; uiNode_t* component; const char* name; const char* type; if (UI_GetParamNumber(context) != 2) { Com_Printf("UI_AbstractNodeCallCreateChild: Invalid number of parameters\n"); return; } name = UI_GetParam(context, 1); type = UI_GetParam(context, 2); uiNode_t* existingNode = UI_GetNode(node, name); if (existingNode != nullptr) { Com_Printf("UI_AbstractNodeCallCreateChild: Node with name '%s' already exists\n", name); } component = UI_GetComponent(type); if (component) { child = UI_CloneNode(component, node->root, true, name, true); } else { child = UI_AllocNode(name, type, true); } if (child == nullptr) { Com_Printf("UI_AbstractNodeCallCreateChild: Impossible to create the node\n"); return; } UI_AppendNode(node, child); }
static void UI_AbstractNodeCallDeleteTimed (uiNode_t* node, const uiCallContext_t* context) { if (UI_GetParamNumber(context) != 1) { Com_Printf("UI_AbstractNodeCallDeleteTimed: Invalid number of parameters\n"); return; } const char* msStr = UI_GetParam(context, 1); const int ms = atoi(msStr); if (ms <= 0) { UI_DeleteNode(node); } else { node->deleteTime = CL_Milliseconds() + ms; } }
static void UI_OptionTreeSetSelectedValue (uiNode_t *node, const uiCallContext_t *context) { uiOptionIterator_t iterator; uiNode_t *option; uiNode_t *firstOption; const char* value; int pos, i; if (UI_GetParamNumber(context) != 1) { Com_Printf("UI_OptionTreeSetSelectedValue: Invalide number of param\n"); return; } value = UI_GetParam(context, 1); /* is the option exists */ firstOption = UI_OptionTreeNodeGetFirstOption(node); UI_InitOptionIteratorAtIndex(0, firstOption, &iterator); /** @todo merge that into the Init iterator function */ iterator.skipCollapsed = qfalse; option = UI_FindOptionByValue(&iterator, value); /* update the selection */ if (option) { UI_AbstractOptionSetCurrentValue(node, OPTIONEXTRADATA(option).value); } else { Com_Printf("UI_OptionTreeSetSelectedValue: Option value \"%s\" not found\n", value); return; } /* expend parents */ for (i = 0; i < iterator.depthPos; i++) OPTIONEXTRADATA(iterator.depthCache[i]).collapsed = qfalse; UI_OptionTreeNodeUpdateCache(node); UI_OptionTreeNodeUpdateScroll(node); /* fix scroll bar */ firstOption = UI_OptionTreeNodeGetFirstOption(node); UI_InitOptionIteratorAtIndex(0, firstOption, &iterator); pos = UI_FindOptionPosition(&iterator, option); if (pos == -1) return; if (pos < EXTRADATA(node).scrollY.viewPos || pos >= EXTRADATA(node).scrollY.viewPos + EXTRADATA(node).scrollY.viewSize) { qboolean updated; updated = UI_SetScroll(&EXTRADATA(node).scrollY, pos, -1, -1); if (updated && EXTRADATA(node).onViewChange) UI_ExecuteEventActions(node, EXTRADATA(node).onViewChange); } }
/** * @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, bool addNewLine, const uiCallContext_t *context) { static char cmd[256]; int length = sizeof(cmd) - (addNewLine ? 2 : 1); static char propertyName[256]; 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 (char const* const rest = Q_strstart(propertyName, "cvar:")) { cvar_t const* const cvar = Cvar_Get(rest); const int l = snprintf(cout, length, "%s", cvar->string); cout += l; cin = next; length -= l; continue; } else if (char const* const path = Q_strstart(propertyName, "node:")) { 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 (char const* const command = Q_strstart(propertyName, "path:")) { if (context->source) { 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); }
/** * @return A string, else an empty string * @todo this should not work very well, because too much va are used * then we should locally cache values, or manage a temporary string structure */ const char* UI_GetStringFromExpression (uiAction_t *expression, const uiCallContext_t *context) { switch (expression->type & EA_HIGHT_MASK) { case EA_VALUE: switch (expression->type) { case EA_VALUE_VAR: { uiValue_t *variable = UI_GetVariable(context, expression->d.terminal.d1.integer); switch (variable->type) { case EA_VALUE_STRING: if (variable->value.string == nullptr) { Com_Printf("UI_GetStringFromExpression: String variable not initialized. Empty string returned"); return ""; } return variable->value.string; case EA_VALUE_FLOAT: { const float number = variable->value.number; const int integer = number; /** @todo should we add a delta? */ if (number == integer) return va("%i", integer); else return va("%f", number); } case EA_VALUE_CVAR: { cvar_t *cvar = variable->value.cvar; if (cvar == nullptr) { Com_Printf("UI_GetStringFromExpression: Cvar variable not initialized. Empty string returned"); return ""; } return cvar->string; } default: Com_Printf("UI_GetStringFromExpression: Unsupported variable type: %i. Empty string returned", variable->type); return ""; } } case EA_VALUE_STRING: case EA_VALUE_STRING_WITHINJECTION: { const char* string = expression->d.terminal.d1.constString; if (expression->type == EA_VALUE_STRING_WITHINJECTION) string = UI_GenInjectedString(string, false, context); return string; } case EA_VALUE_FLOAT: { const float number = expression->d.terminal.d1.number; const int integer = number; /** @todo should we add a delta? */ if (number == integer) return va("%i", integer); else return va("%f", number); } case EA_VALUE_CVARNAME: case EA_VALUE_CVARNAME_WITHINJECTION: { cvar_t *cvar = nullptr; const char *cvarName = expression->d.terminal.d1.constString; if (expression->type == EA_VALUE_CVARNAME_WITHINJECTION) cvarName = UI_GenInjectedString(cvarName, false, context); cvar = Cvar_Get(cvarName, "", 0, "Cvar from UI script expression"); return cvar->string; } case EA_VALUE_PATHPROPERTY: case EA_VALUE_PATHPROPERTY_WITHINJECTION: { uiNode_t *node; const value_t *property; const char* string; node = UI_GetNodeFromExpression(expression, context, &property); if (!node) { Com_Printf("UI_GetStringFromExpression: Node wasn't found; Empty string returned\n"); return ""; } if (!property) { Com_Printf("UI_GetStringFromExpression: Property wasn't found; Empty string returned\n"); return ""; } string = UI_GetStringFromNodeProperty(node, property); if (string == nullptr) { Com_Printf("UI_GetStringFromExpression: String getter for '%s@%s' property do not exists; '' returned\n", UI_Node_GetWidgetName(node), property->string); return ""; } return string; } break; case EA_VALUE_PARAM: return UI_GetParam(context, expression->d.terminal.d1.integer); case EA_VALUE_PARAMCOUNT: return va("%i", UI_GetParamNumber(context)); } break; case EA_OPERATOR_UNARY: switch (expression->type) { case EA_OPERATOR_PATHPROPERTYFROM: { uiNode_t *node; const value_t *property; node = UI_GetNodeFromExpression(expression, context, &property); return UI_GetStringFromNodeProperty(node, property); } default: Com_Error(ERR_FATAL, "UI_GetFloatFromExpression: (EA_OPERATOR_UNARY) Invalid expression type %i", expression->type); } case EA_OPERATOR_BOOLEAN2BOOLEAN: case EA_OPERATOR_FLOAT2BOOLEAN: case EA_OPERATOR_STRING2BOOLEAN: { const bool v = UI_GetBooleanFromExpression(expression, context); return (v)?"1":"0"; } case EA_OPERATOR_FLOAT2FLOAT: { const float number = UI_GetFloatFromExpression(expression, context); const int integer = number; /** @todo should we add a delta? */ if (number == integer) return va("%i", integer); else return va("%f", number); } } Com_Printf("UI_GetStringFromExpression: Unsupported expression type: %i", expression->type); return ""; }
/** * @return A float value, else 0 */ float UI_GetFloatFromExpression (uiAction_t *expression, const uiCallContext_t *context) { switch (expression->type & EA_HIGHT_MASK) { case EA_VALUE: switch (expression->type) { case EA_VALUE_VAR: { uiValue_t *variable = UI_GetVariable(context, expression->d.terminal.d1.integer); switch (variable->type) { case EA_VALUE_STRING: if (variable->value.string == nullptr) { Com_Printf("UI_GetFloatFromExpression: String variable not initialized. '0' returned"); return 0; } return atof(variable->value.string); case EA_VALUE_FLOAT: return variable->value.number; case EA_VALUE_CVAR: { cvar_t *cvar = variable->value.cvar; if (cvar == nullptr) { Com_Printf("UI_GetFloatFromExpression: Cvar variable not initialized. '0' returned"); return 0; } return cvar->value; } default: Com_Printf("UI_GetFloatFromExpression: Unsupported variable type: %i. '0' returned", variable->type); return 0; } } case EA_VALUE_STRING: case EA_VALUE_STRING_WITHINJECTION: { const char* string = expression->d.terminal.d1.constString; if (expression->type == EA_VALUE_STRING_WITHINJECTION) string = UI_GenInjectedString(string, false, context); return atof(string); } case EA_VALUE_FLOAT: return expression->d.terminal.d1.number; case EA_VALUE_CVARNAME: case EA_VALUE_CVARNAME_WITHINJECTION: { cvar_t *cvar = nullptr; const char *cvarName = expression->d.terminal.d1.constString; if (expression->type == EA_VALUE_CVARNAME_WITHINJECTION) cvarName = UI_GenInjectedString(cvarName, false, context); cvar = Cvar_Get(cvarName, "", 0, "Cvar from UI script expression"); return cvar->value; } case EA_VALUE_PATHPROPERTY: case EA_VALUE_PATHPROPERTY_WITHINJECTION: { uiNode_t *node; const value_t *property; node = UI_GetNodeFromExpression(expression, context, &property); if (!node) { Com_Printf("UI_GetFloatFromParam: Node wasn't found; '0'\n"); return 0; } if (!property) { Com_Printf("UI_GetFloatFromParam: Property wasn't found; '0' returned\n"); return 0; } return UI_GetFloatFromNodeProperty(node, property); } case EA_VALUE_PARAM: { const int paramId = expression->d.terminal.d1.integer; const char *string = UI_GetParam(context, paramId); if (string[0] == '\0') { Com_Printf("UI_GetFloatFromParam: Param '%i' is out of range, or empty; '0' returned\n", paramId); return 0; } return atof(string); } case EA_VALUE_PARAMCOUNT: return UI_GetParamNumber(context); } break; case EA_OPERATOR_FLOAT2FLOAT: { const float value1 = UI_GetFloatFromExpression(expression->d.nonTerminal.left, context); const float value2 = UI_GetFloatFromExpression(expression->d.nonTerminal.right, context); switch (expression->type) { case EA_OPERATOR_ADD: return value1 + value2; case EA_OPERATOR_SUB: return value1 - value2; case EA_OPERATOR_MUL: return value1 * value2; case EA_OPERATOR_DIV: if (value2 == 0) { Com_Printf("UI_GetFloatFromExpression: Div by 0. '0' returned"); return 0; } else return value1 / value2; case EA_OPERATOR_MOD: { const int v1 = value1; const int v2 = value2; /** @todo do we have some check to do? */ return v1 % v2; } } } break; case EA_OPERATOR_UNARY: switch (expression->type) { case EA_OPERATOR_PATHPROPERTYFROM: { uiNode_t *node; const value_t *property; node = UI_GetNodeFromExpression(expression, context, &property); return UI_GetFloatFromNodeProperty(node, property); } default: Com_Error(ERR_FATAL, "UI_GetFloatFromExpression: (EA_OPERATOR_UNARY) Invalid expression type %i", expression->type); } } Com_Printf("UI_GetFloatFromExpression: Unsupported expression type: %i. '0' returned", expression->type); return 0; }