/** * @brief display value of a node property from the command line */ static void UI_NodeGetProperty_f (void) { uiNode_t* node; const value_t* property; const char* sValue; float fValue; if (Cmd_Argc() != 2) { Com_Printf("Usage: %s <nodepath@prop>\n", Cmd_Argv(0)); return; } UI_ReadNodePath(Cmd_Argv(1), nullptr, &node, &property); if (node == nullptr) { Com_Printf("UI_NodeGetProperty_f: Node from path '%s' doesn't exist\n", Cmd_Argv(1)); return; } if (property == nullptr) { Com_Printf("UI_NodeGetProperty_f: Property from path '%s' doesn't exist\n", Cmd_Argv(1)); return; } /* check string value */ sValue = UI_GetStringFromNodeProperty(node, property); if (sValue) { Com_Printf("\"%s\" is \"%s\"\n", Cmd_Argv(1), sValue); return; } /* check float value */ fValue = UI_GetFloatFromNodeProperty(node, property); Com_Printf("\"%s\" is \"%f\"\n", Cmd_Argv(1), fValue); }
/** * @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 ""; }