Example #1
0
/**
 * @brief Search a file name inside pics/ according to the sprite name
 * If it exists, generate a "single" sprite using the size of the image
 * @param name Name of the sprite
 * @return A sprite, else nullptr
 */
static uiSprite_t* UI_AutoGenerateSprite (const char* name)
{
	uiSprite_t* sprite = nullptr;
	const char* suffix[SPRITE_STATUS_MAX] = {"", "_hovered", "_disabled", "_clicked"};
	char basePicNameBuf[MAX_QPATH];
	const image_t* pic;
	int i;

	Q_strncpyz(basePicNameBuf, name, sizeof(basePicNameBuf));

	pic = UI_LoadImage(basePicNameBuf);
	if (pic == nullptr)
		return nullptr;

	sprite = UI_AllocStaticSprite(basePicNameBuf);
	sprite->image[SPRITE_STATUS_NORMAL] = UI_AllocStaticString(basePicNameBuf, 0);
	sprite->size[0] = pic->width;
	sprite->size[1] = pic->height;
	for (i = 1; i < SPRITE_STATUS_MAX; i++) {
		char picNameBuf[MAX_QPATH];
		Com_sprintf(picNameBuf, sizeof(picNameBuf), "%s%s", basePicNameBuf, suffix[i]);
		pic = UI_LoadImage(picNameBuf);
		if (pic != nullptr)
			sprite->image[i] = UI_AllocStaticString(picNameBuf, 0);
	}
	return sprite;
}
Example #2
0
/**
 * Parse a string according to a property type, and allocate a raw value to the static memory
 *
 * @param action Action to initialize
 * @param node Current node we are parsing, only used for error message
 * @param property Type of the value to parse, if nullptr the string is not stored as string
 * @param string String value to parse
 * @return True if the action is initialized
 * @todo remove node param and catch error where we call that function
 */
bool UI_InitRawActionValue (uiAction_t* action, uiNode_t* node, const value_t* property, const char* string)
{
	if (property == nullptr) {
		action->type = EA_VALUE_STRING;
		action->d.terminal.d1.data = UI_AllocStaticString(string, 0);
		action->d.terminal.d2.integer = 0;
		return true;
	}

	if (property->type == V_UI_SPRITEREF) {
		uiSprite_t* sprite = UI_GetSpriteByName(string);
		if (sprite == nullptr) {
			Com_Printf("UI_ParseSetAction: sprite '%s' not found (%s)\n", string, UI_GetPath(node));
			return false;
		}
		action->type = EA_VALUE_RAW;
		action->d.terminal.d1.data = sprite;
		action->d.terminal.d2.integer = property->type;
		return true;
	} else {
		const int baseType = property->type & V_UI_MASK;
		if (baseType != 0 && baseType != V_UI_CVAR) {
			Com_Printf("UI_ParseRawValue: setter for property '%s' (type %d, 0x%X) is not supported (%s)\n", property->string, property->type, property->type, UI_GetPath(node));
			return false;
		}
		ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t) (property->type & V_BASETYPEMASK));
		action->type = EA_VALUE_RAW;
		action->d.terminal.d1.data = ui_global.curadata;
		action->d.terminal.d2.integer = property->type;
		/** @todo we should hide use of ui_global.curadata */
		ui_global.curadata += Com_EParseValue(ui_global.curadata, string, (valueTypes_t) (property->type & V_BASETYPEMASK), 0, property->size);
		return true;
	}
}
Example #3
0
/**
 * @brief Search a file name inside pics/ according to the sprite name
 * If it exists, generate a "single" sprite using the size of the image
 * @param name Name of the sprite
 * @return A sprite, else NULL
 */
static uiSprite_t* UI_AutoGenerateSprite (const char* name)
{
	uiSprite_t* sprite = NULL;
	const char* suffix[SPRITE_STATUS_MAX] = {"", "_hovered", "_disabled", "_clicked"};
	int i;

	const char *picName = name;
	const image_t *pic = UI_LoadImage(picName);
	if (pic == NULL)
		return NULL;

	sprite = UI_AllocStaticSprite(name);
	sprite->image[SPRITE_STATUS_NORMAL] = UI_AllocStaticString(picName, 0);
	sprite->size[0] = pic->width;
	sprite->size[1] = pic->height;
	for (i = 1; i < SPRITE_STATUS_MAX; i++) {
		picName = va("%s%s", name, suffix[i]);
		pic = UI_LoadImage(picName);
		if (pic != NULL)
			sprite->image[i] = UI_AllocStaticString(picName, 0);
	}
	return sprite;
}
Example #4
0
static void UI_ModelNodeLoaded (uiNode_t *node)
{
	/* a tag without but not a submodel */
	if (EXTRADATA(node).tag != NULL && node->behaviour != node->parent->behaviour) {
		Com_Printf("UI_ModelNodeLoaded: '%s' use a tag but is not a submodel. Tag removed.\n", UI_GetPath(node));
		EXTRADATA(node).tag = NULL;
	}

	if (EXTRADATA(node).oldRefValue == NULL)
		EXTRADATA(node).oldRefValue = UI_AllocStaticString("", MAX_OLDREFVALUE);

	/* no tag but no size */
	if (EXTRADATA(node).tag == NULL && (node->size[0] == 0 || node->size[1] == 0)) {
		Com_Printf("UI_ModelNodeLoaded: Please set a pos and size to the node '%s'. Note: 'origin' is a relative value to the center of the node\n", UI_GetPath(node));
	}
}
Example #5
0
/**
 * @brief Parse actions and return action list
 * @return The first element from a list of action
 * @sa ea_t
 * @todo need cleanup, compute action out of the final memory; reduce number of var
 */
static uiAction_t* UI_ParseActionList (uiNode_t* node, const char** text, const char** token)
{
	const char* errhead = "UI_ParseActionList: unexpected end of file (in event)";
	uiAction_t* firstAction;
	uiAction_t* lastAction;
	uiAction_t* action;

	lastAction = nullptr;
	firstAction = nullptr;

	/* prevent bad position */
	if ((*token)[0] != '{') {
		Com_Printf("UI_ParseActionList: token \"{\" expected, but \"%s\" found (in event) (node: %s)\n", *token, UI_GetPath(node));
		return nullptr;
	}

	while (true) {
		bool result;
		int type = EA_NULL;

		/* get new token */
		*token = Com_EParse(text, errhead, nullptr);
		if (!*token)
			return nullptr;

		if ((*token)[0] == '}')
			break;

		type = UI_GetActionTokenType(*token, EA_ACTION);
		/* setter form */
		if (type == EA_NULL && (*token)[0] == '*')
			type = EA_ASSIGN;

		/* unknown, we break the parsing */
		if (type == EA_NULL) {
			Com_Printf("UI_ParseActionList: unknown token \"%s\" ignored (in event) (node: %s)\n", *token, UI_GetPath(node));
			return nullptr;
		}

		/* add the action */
		action = UI_AllocStaticAction();
		/** @todo better to append the action after initialization */
		if (lastAction)
			lastAction->next = action;
		if (!firstAction)
			firstAction = action;
		action->type = type;

		/* decode action */
		switch (action->type) {
		case EA_CMD:
			/* get parameter values */
			*token = Com_EParse(text, errhead, nullptr);
			if (!*text)
				return nullptr;

			/* get the value */
			action->d.terminal.d1.constString = UI_AllocStaticString(*token, 0);
			break;

		case EA_ASSIGN:
			result = UI_ParseSetAction(node, action, text, token, errhead);
			if (!result)
				return nullptr;
			break;

		case EA_CALL:
			result = UI_ParseCallAction(node, action, text, token, errhead);
			if (!result)
				return nullptr;
			break;

		case EA_DELETE:
			{
				uiAction_t* expression;
				expression = UI_ParseExpression(text);
				if (expression == nullptr)
					return nullptr;

				if (expression->type != EA_VALUE_CVARNAME) {
					Com_Printf("UI_ParseActionList: \"delete\" keyword only support cvarname (node: %s)\n", UI_GetPath(node));
					return nullptr;
				}

				action->d.nonTerminal.left = expression;
				break;
			}

		case EA_ELIF:
			/* check previous action */
			if (!lastAction || (lastAction->type != EA_IF && lastAction->type != EA_ELIF)) {
				Com_Printf("UI_ParseActionList: 'elif' must be set after an 'if' or an 'elif' (node: %s)\n", UI_GetPath(node));
				return nullptr;
			}
			/* then it execute EA_IF, no break */
		case EA_WHILE:
		case EA_IF:
			{
				uiAction_t* expression;

				/* get the condition */
				expression = UI_ParseExpression(text);
				if (expression == nullptr)
					return nullptr;
				action->d.nonTerminal.left = expression;

				/* get the action block */
				*token = Com_EParse(text, errhead, nullptr);
				if (!*text)
					return nullptr;
				action->d.nonTerminal.right = UI_ParseActionList(node, text, token);
				if (action->d.nonTerminal.right == nullptr) {
					switch (action->type) {
					case EA_IF:
						Com_Printf("UI_ParseActionList: block expected after \"if\" (node: %s)\n", UI_GetPath(node));
						break;
					case EA_ELIF:
						Com_Printf("UI_ParseActionList: block expected after \"elif\" (node: %s)\n", UI_GetPath(node));
						break;
					case EA_WHILE:
						Com_Printf("UI_ParseActionList: block expected after \"while\" (node: %s)\n", UI_GetPath(node));
						break;
					default:
						Com_Printf("UI_ParseActionList: cannot determine statement type (node: %s)\n", UI_GetPath(node));
					}
					return nullptr;
				}
				break;
			}

		case EA_FORCHILDIN:
			{
				uiAction_t* expression;

				/* get the node */
				expression = UI_ParseExpression(text);
				if (expression == nullptr) {
					return nullptr;
				}
				action->d.nonTerminal.left = expression;

				/* check the type */
				type = action->d.nonTerminal.left->type;
				if (type != EA_VALUE_PATHNODE && type != EA_VALUE_PATHNODE_WITHINJECTION) {
					Com_Printf("UI_ParseActionList: Node property expected. Type '%x' found\n", type);
					return nullptr;
				}

				/* get the action block */
				*token = Com_EParse(text, errhead, nullptr);
				if (!*text)
					return nullptr;
				action->d.nonTerminal.right = UI_ParseActionList(node, text, token);
				if (action->d.nonTerminal.right == nullptr) {
					Com_Printf("UI_ParseActionList: block expected after \"forchildin\" (node: %s)\n", UI_GetPath(node));
					return nullptr;
				}
				break;
			}

		case EA_ELSE:
			/* check previous action */
			if (!lastAction || (lastAction->type != EA_IF && lastAction->type != EA_ELIF)) {
				Com_Printf("UI_ParseActionList: 'else' must be set after an 'if' or an 'elif' (node: %s)\n", UI_GetPath(node));
				return nullptr;
			}

			/* get the action block */
			*token = Com_EParse(text, errhead, nullptr);
			if (!*text)
				return nullptr;
			action->d.nonTerminal.left = nullptr;
			action->d.nonTerminal.right = UI_ParseActionList(node, text, token);
			if (action->d.nonTerminal.right == nullptr) {
				Com_Printf("UI_ParseActionList: block expected after \"else\" (node: %s)\n", UI_GetPath(node));
				return nullptr;
			}
			break;

		default:
			assert(false);
		}

		/* step */
		lastAction = action;
	}

	assert((*token)[0] == '}');

	/* return non nullptr value */
	if (firstAction == nullptr) {
		firstAction = UI_AllocStaticAction();
	}

	return firstAction;
}
Example #6
0
/**
 * @brief Parser for setter command
 */
static bool UI_ParseSetAction (uiNode_t* node, uiAction_t* action, const char** text, const char** token, const char* errhead)
{
	const value_t* property;
	int type;
	uiAction_t* localAction;

	assert((*token)[0] == '*');

	Com_UnParseLastToken();
	action->d.nonTerminal.left = UI_ParseExpression(text);

	type = action->d.nonTerminal.left->type;
	if (type != EA_VALUE_CVARNAME && type != EA_VALUE_CVARNAME_WITHINJECTION
		&& type != EA_VALUE_PATHPROPERTY && type != EA_VALUE_PATHPROPERTY_WITHINJECTION) {
		Com_Printf("UI_ParseSetAction: Cvar or Node property expected. Type '%i' found\n", type);
		return false;
	}

	/* must use "equal" char between name and value */
	*token = Com_EParse(text, errhead, nullptr);
	if (!*text)
		return false;
	if (!Q_streq(*token, "=")) {
		Com_Printf("UI_ParseSetAction: Assign sign '=' expected between variable and value. '%s' found in node %s.\n", *token, UI_GetPath(node));
		return false;
	}

	/* get the value */
	if (type == EA_VALUE_CVARNAME || type == EA_VALUE_CVARNAME_WITHINJECTION) {
		action->d.nonTerminal.right = UI_ParseExpression(text);
		return true;
	}

	property = (const value_t*) action->d.nonTerminal.left->d.terminal.d2.data;

	*token = Com_EParse(text, errhead, nullptr);
	if (!*text)
		return false;

	if (Q_streq(*token, "{")) {
		uiAction_t* actionList;

		if (property != nullptr && property->type != V_UI_ACTION) {
			Com_Printf("UI_ParseSetAction: Property %s@%s do not expect code block.\n", UI_GetPath(node), property->string);
			return false;
		}

		actionList = UI_ParseActionList(node, text, token);
		if (actionList == nullptr)
			return false;

		localAction = UI_AllocStaticAction();
		localAction->type = EA_VALUE_RAW;
		localAction->d.terminal.d1.data = actionList;
		localAction->d.terminal.d2.integer = V_UI_ACTION;
		action->d.nonTerminal.right = localAction;

		return true;
	}

	if (Q_streq(*token, "(")) {
		Com_UnParseLastToken();
		action->d.nonTerminal.right = UI_ParseExpression(text);
		return true;
	}

	/* @todo everything should come from UI_ParseExpression */

	if (UI_IsInjectedString(*token)) {
		localAction = UI_AllocStaticAction();
		localAction->type = EA_VALUE_STRING_WITHINJECTION;
		localAction->d.terminal.d1.data = UI_AllocStaticString(*token, 0);
		action->d.nonTerminal.right = localAction;
		return true;
	}

	localAction = UI_AllocStaticAction();
	UI_InitRawActionValue(localAction, node, property, *token);
	action->d.nonTerminal.right = localAction;
	return true;
}
Example #7
0
/**
 * @brief Read a value from the stream and init an action with it
 * @return An initialized action else nullptr
 */
static uiAction_t *UI_ParseValueExpression (const char **text)
{
	const char* token;
	uiAction_t *expression = UI_AllocStaticAction();

	token = Com_Parse(text);
	if (*text == nullptr) {
		Com_Printf("UI_ParseTerminalExpression: Token expected\n");
		return nullptr;
	}

	/* it is a const string (or an injection tag for compatibility) */
	if (Com_GetType(text) == TT_QUOTED_WORD || token[0] == '<') {
		expression->d.terminal.d1.constString = UI_AllocStaticString(token, 0);
		if (UI_IsInjectedString(token))
			expression->type = EA_VALUE_STRING_WITHINJECTION;
		else
			expression->type = EA_VALUE_STRING;
		return expression;
	}

	/* it is a param */
	if (!Q_strncasecmp(token, "param", 5)) {
		if (!Q_strcasecmp(token, "paramcount")) {
			expression->type = EA_VALUE_PARAMCOUNT;
			return expression;
		} else if (token[5] >= '1' && token[5] <= '9') {
			int i;
			if (sscanf(token + 5, "%i", &i) == 1) {
				/* token range 1-9 already avoid 0 */
				assert(i != 0);
				/** @todo when it is possible, we must check range of param id */
				expression->type = EA_VALUE_PARAM;
				expression->d.terminal.d1.integer = i;
				return expression;
			}
		}
	}

	/* it is a cvarname */
	if (char const* const cvarName = Q_strstart(token, "*cvar:")) {
		expression->d.terminal.d1.constString = UI_AllocStaticString(cvarName, 0);
		if (UI_IsInjectedString(cvarName))
			expression->type = EA_VALUE_CVARNAME_WITHINJECTION;
		else
			expression->type = EA_VALUE_CVARNAME;
		return expression;
	}

	/* it is a node property or it is a OLD syntax node property */
	/** @todo We MUST remove the OLD code as fast as possible */
	if (char const* path = Q_strstart(token, "*")) {
		const char *propertyName;
#if 0	/* it looks useless, an unused cache */
		const value_t *property;
#endif

		char const* const relativeToNode = Q_strstart(path, "node:");
		if (relativeToNode)
			path = relativeToNode;

		if (UI_IsInjectedString(path))
			expression->type = EA_VALUE_PATHPROPERTY_WITHINJECTION;
		else
			expression->type = EA_VALUE_PATHPROPERTY;
		if (!relativeToNode) {
			Com_Printf("UI_ParseExpression: Old syntax, please prefix '%s' with \"*node:root.\" \n", token);
			path = va("root.%s", path);
		}
		expression->d.terminal.d1.constString = UI_AllocStaticString(path, 0);

		/* get property name */
		propertyName = strchr(path, '@');
		if (propertyName == nullptr) {
			if (expression->type == EA_VALUE_PATHPROPERTY_WITHINJECTION)
				expression->type = EA_VALUE_PATHNODE_WITHINJECTION;
			else
				expression->type = EA_VALUE_PATHNODE;
			return expression;
		}
		propertyName++;

		return expression;
	}

	/* unsigned and signed number */
	if ((token[0] >= '0' && token[0] <= '9')
		|| (token[0] == '-' && token[1] >= '0' && token[1] <= '9')) {
		/** @todo use a better check - e.g. Com_ParseValue with V_INT or V_FLOAT */
		float f = atof(token);
		expression->d.terminal.d1.number = f;
		expression->type = EA_VALUE_FLOAT;
		return expression;
	}

	/* boolean */
	if (Q_streq(token, "true")) {
		expression->d.terminal.d1.number = 1.0;
		expression->type = EA_VALUE_FLOAT;
		return expression;
	}
	if (Q_streq(token, "false")) {
		expression->d.terminal.d1.number = 0.0;
		expression->type = EA_VALUE_FLOAT;
		return expression;
	}

	Com_Error(ERR_FATAL, "UI_ParseValueExpression: Token \"%s\" unknown. String must use quotes, cvar and nodes must use prefix.\n", token);
}
Example #8
0
/**
 * @brief Call to update a cloned node
 */
void uiModelNode::clone (const uiNode_t* source, uiNode_t* clone)
{
	uiLocatedNode::clone(source, clone);
	if (!clone->dynamic)
		EXTRADATA(clone).oldRefValue = UI_AllocStaticString("", MAX_OLDREFVALUE);
}
Example #9
0
/**
 * @brief Call to update a cloned node
 */
static void UI_ModelNodeClone (const uiNode_t *source, uiNode_t *clone)
{
	localBehaviour->super->clone(source, clone);
	if (!clone->dynamic)
		EXTRADATA(clone).oldRefValue = UI_AllocStaticString("", MAX_OLDREFVALUE);
}