Beispiel #1
0
/**
 * Apply an action value to a node property. If the tuple property/value allow it, the function
 * pre compute the value and update the action value to speed up the next call.
 * @param node Node to edit
 * @param property Property of the node to edit
 * @param value Action value containing the value to set to the node property
 * @param context Call context of the script
 * @todo refactoring it to remove "context", we should only call that function when the action
 * value is a leaf (then a value, and not an expression)
 */
static void UI_NodeSetPropertyFromActionValue (uiNode_t *node, const value_t *property, const uiCallContext_t *context, uiAction_t* value)
{
	/* @todo we can use a new EA_VALUE type to flag already parsed values, we dont need to do it again and again */
	/* pre compute value if possible */
	if (value->type == EA_VALUE_STRING) {
		const char* string = value->d.terminal.d1.constString;
		if ((property->type & V_UI_MASK) == V_UI_CVAR && Q_strstart(string, "*cvar:")) {
			Com_GetValue<void*>(node, property) = value->d.terminal.d1.data;
		} else {
			/** @todo here we must catch error in a better way, and using cvar for error code to create unittest automations */
			UI_InitRawActionValue(value, node, property, string);
		}
	}

	/* decode RAW value */
	if (value->type == EA_VALUE_RAW) {
		const void *rawValue = value->d.terminal.d1.constData;
		const int rawType = value->d.terminal.d2.integer;
		UI_NodeSetPropertyFromRAW(node, property, rawValue, rawType);
	}
	/* else it is an expression */
	else {
		/** @todo we should improve if when the prop is a boolean/int/float */
		const char* string = UI_GetStringFromExpression(value, context);
		UI_NodeSetProperty(node, property, string);
	}
}
Beispiel #2
0
static inline void UI_ExecuteSetAction (const uiAction_t* action, const uiCallContext_t *context)
{
	const char* path;
	uiNode_t *node;
	const value_t *property;
	const uiAction_t *left;
	uiAction_t *right;

	left = action->d.nonTerminal.left;
	if (left == NULL) {
		Com_Printf("UI_ExecuteSetAction: Action without left operand skipped.\n");
		return;
	}

	right = action->d.nonTerminal.right;
	if (right == NULL) {
		Com_Printf("UI_ExecuteSetAction: Action without right operand skipped.\n");
		return;
	}

	if (left->type == EA_VALUE_CVARNAME || left->type == EA_VALUE_CVARNAME_WITHINJECTION) {
		const char *cvarName;
		const char* textValue;

		if (left->type == EA_VALUE_CVARNAME)
			cvarName = left->d.terminal.d1.constString;
		else
			cvarName = UI_GenInjectedString(left->d.terminal.d1.constString, false, context);

		textValue = UI_GetStringFromExpression(right, context);

		if (textValue[0] == '_')
			textValue = _(textValue + 1);

		Cvar_ForceSet(cvarName, textValue);
		return;
	}

	/* search the node */
	if (left->type == EA_VALUE_PATHPROPERTY)
		path = left->d.terminal.d1.constString;
	else if (left->type == EA_VALUE_PATHPROPERTY_WITHINJECTION)
		path = UI_GenInjectedString(left->d.terminal.d1.constString, false, context);
	else
		Com_Error(ERR_FATAL, "UI_ExecuteSetAction: Property setter with wrong type '%d'", left->type);

	UI_ReadNodePath(path, context->source, &node, &property);
	if (!node) {
		Com_Printf("UI_ExecuteSetAction: node \"%s\" doesn't exist (source: %s)\n", path, UI_GetPath(context->source));
		return;
	}
	if (!property) {
		Com_Printf("UI_ExecuteSetAction: property \"%s\" doesn't exist (source: %s)\n", path, UI_GetPath(context->source));
		return;
	}

	UI_NodeSetPropertyFromActionValue(node, property, context, right);
}
Beispiel #3
0
static inline void UI_ExecuteCallAction (const uiAction_t* action, const uiCallContext_t *context)
{
	uiNode_t* callNode = NULL;
	uiAction_t* param;
	uiAction_t* left = action->d.nonTerminal.left;
	uiCallContext_t newContext;
	const value_t* callProperty = NULL;
	const char* path = left->d.terminal.d1.constString;

	if (left->type == EA_VALUE_PATHPROPERTY || left->type == EA_VALUE_PATHNODE)
		path = left->d.terminal.d1.constString;
	else if (left->type == EA_VALUE_PATHPROPERTY_WITHINJECTION || left->type == EA_VALUE_PATHNODE_WITHINJECTION)
		path = UI_GenInjectedString(left->d.terminal.d1.constString, false, context);
	UI_ReadNodePath(path, context->source, &callNode, &callProperty);

	if (callNode == NULL) {
		Com_Printf("UI_ExecuteCallAction: Node from path \"%s\" not found (relative to \"%s\").\n", path, UI_GetPath(context->source));
		return;
	}

	if (callProperty != NULL && callProperty->type != V_UI_ACTION && callProperty->type != V_UI_NODEMETHOD) {
		Com_Printf("UI_ExecuteCallAction: Call operand %d unsupported. (%s)\n", callProperty->type, UI_GetPath(callNode));
		return;
	}

	newContext.source = callNode;
	newContext.params = NULL;
	newContext.paramNumber = 0;
	newContext.varNumber = 0;
	newContext.varPosition = context->varPosition + context->varNumber;

	if (action->type == EA_LISTENER) {
		newContext.useCmdParam = context->useCmdParam;

		if (!newContext.useCmdParam) {
			linkedList_t *p = context->params;
			while (p) {
				const char* value = (char*) p->data;
				LIST_AddString(&newContext.params, value);
				newContext.paramNumber++;
				p = p->next;
			}
		}
	} else {
		newContext.useCmdParam = false;

		param = action->d.nonTerminal.right;
		while (param) {
			const char* value;
			value = UI_GetStringFromExpression(param, context);
			LIST_AddString(&newContext.params, value);
			newContext.paramNumber++;
			param = param->next;
		}
	}

	if (callProperty == NULL || callProperty->type == V_UI_ACTION) {
		uiAction_t const* const actionsRef = callProperty ? Com_GetValue<uiAction_t*>(callNode, callProperty) : callNode->onClick;
		UI_ExecuteActions(actionsRef, &newContext);
	} else if (callProperty->type == V_UI_NODEMETHOD) {
		uiNodeMethod_t func = (uiNodeMethod_t) callProperty->ofs;
		func(callNode, &newContext);
	} else {
		/* unreachable, already checked few line before */
		assert(false);
	}

	LIST_Delete(&newContext.params);
}
Beispiel #4
0
/**
 * @brief Check if an expression is true
 * @return True if the expression is true
 */
bool UI_GetBooleanFromExpression (uiAction_t *expression, const uiCallContext_t *context)
{
	if (expression == nullptr)
		return false;

	switch (expression->type & EA_HIGHT_MASK) {
	case EA_VALUE:
		return UI_GetFloatFromExpression(expression, context) != 0;

	case EA_OPERATOR_BOOLEAN2BOOLEAN:
		{
#define VALUE1 UI_GetBooleanFromExpression(expression->d.nonTerminal.left, context)
#define VALUE2 UI_GetBooleanFromExpression(expression->d.nonTerminal.right, context)

			switch (expression->type) {
			case EA_OPERATOR_AND:
				return VALUE1 && VALUE2;
			case EA_OPERATOR_OR:
				return VALUE1 || VALUE2;
			case EA_OPERATOR_XOR:
				return VALUE1 ^ VALUE2;
			case EA_OPERATOR_NOT:
				return !VALUE1;
			default:
				Com_Error(ERR_FATAL, "UI_GetBooleanFromExpression: (BOOL2BOOL) Invalid expression type");
			}
		}

	case EA_OPERATOR_FLOAT2BOOLEAN:
		{
			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_EQ:
				return value1 == value2;
			case EA_OPERATOR_LE:
				return value1 <= value2;
			case EA_OPERATOR_GE:
				return value1 >= value2;
			case EA_OPERATOR_GT:
				return value1 > value2;
			case EA_OPERATOR_LT:
				return value1 < value2;
			case EA_OPERATOR_NE:
				return value1 != value2;
			default:
				Com_Error(ERR_FATAL, "UI_GetBooleanFromExpression: (FLOAT2BOOL) Invalid expression type");
			}
		}

	case EA_OPERATOR_UNARY:
		switch (expression->type) {
		case EA_OPERATOR_EXISTS:
			{
				const uiAction_t *e = expression->d.nonTerminal.left;
				const char* name;
				assert(e);
				name = e->d.terminal.d1.constString;
				switch (e->type) {
				case EA_VALUE_CVARNAME_WITHINJECTION:
					name = UI_GenInjectedString(name, false, context);
				case EA_VALUE_CVARNAME:
					return Cvar_FindVar(name) != nullptr;
				case EA_VALUE_PATHNODE_WITHINJECTION:
					name = UI_GenInjectedString(name, false, context);
				case EA_VALUE_PATHNODE: {
					uiNode_t* node = nullptr;
					const value_t *property;
					UI_ReadNodePath(name, context->source, &node, &property);
					return node != nullptr;
				}
				default:
					return false;
				}
			}
		case EA_OPERATOR_PATHPROPERTYFROM:
			return UI_GetFloatFromExpression(expression, context) != 0;
		default:
			Com_Error(ERR_FATAL, "UI_GetBooleanFromExpression: (EA_OPERATOR_UNARY) Invalid expression type %i", expression->type);
		}

	case EA_OPERATOR_STRING2BOOLEAN:
		{
			const char* value1 = UI_GetStringFromExpression(expression->d.nonTerminal.left, context);
			const char* value2 = UI_GetStringFromExpression(expression->d.nonTerminal.right, context);

			switch (expression->type) {
			case EA_OPERATOR_STR_EQ:
				return Q_streq(value1, value2);
			case EA_OPERATOR_STR_NE:
				return !Q_streq(value1, value2);
			default:
				Com_Error(ERR_FATAL, "UI_GetBooleanFromExpression: (STRING2BOOL) Invalid expression type");
			}
		}

	default:
		Com_Error(ERR_FATAL, "UI_GetBooleanFromExpression: Unsupported expression type: %i", expression->type);
	}
}
Beispiel #5
0
static inline void UI_ExecuteCallAction (const uiAction_t* action, const uiCallContext_t* context)
{
    uiNode_t* callNode = nullptr;
    uiAction_t* param;
    uiAction_t* left = action->d.nonTerminal.left;
    uiCallContext_t newContext;
    const value_t* callProperty = nullptr;
    value_t luaMethod;
    const char* path = left->d.terminal.d1.constString;

    // clear luaMethod structure before using it
    memset(&luaMethod, 0, sizeof(luaMethod));

    if (left->type == EA_VALUE_PATHPROPERTY || left->type == EA_VALUE_PATHNODE)
        path = left->d.terminal.d1.constString;
    else if (left->type == EA_VALUE_PATHPROPERTY_WITHINJECTION || left->type == EA_VALUE_PATHNODE_WITHINJECTION)
        path = UI_GenInjectedString(left->d.terminal.d1.constString, false, context);

    UI_ReadNodePath(path, context->source, context->tagNode, &callNode, &callProperty, &luaMethod);
    if ((callNode == nullptr) && (!luaMethod.type)) {
        Com_Printf("UI_ExecuteCallAction: Node from path \"%s\" not found (relative to \"%s\").\n", path, UI_GetPath(context->source));
        return;
    }
    if (callProperty != nullptr && callProperty->type != V_UI_ACTION && callProperty->type != V_UI_NODEMETHOD && callProperty->type != V_UI_NODEMETHOD_LUA) {
        Com_Printf("UI_ExecuteCallAction: Call operand %d unsupported. (%s)\n", callProperty->type, UI_GetPath(callNode));
        return;
    }

    newContext.source = callNode;
    newContext.params = nullptr;
    newContext.paramNumber = 0;
    newContext.varNumber = 0;
    newContext.varPosition = context->varPosition + context->varNumber;
    newContext.breakLoop = false;

    if (action->type == EA_LISTENER) {
        newContext.useCmdParam = context->useCmdParam;

        if (!newContext.useCmdParam) {
            linkedList_t* p = context->params;
            while (p) {
                const char* value = (char*) p->data;
                LIST_AddString(&newContext.params, value);
                newContext.paramNumber++;
                p = p->next;
            }
        }
    } else {
        newContext.useCmdParam = false;

        param = action->d.nonTerminal.right;
        while (param) {
            const char* value;
            value = UI_GetStringFromExpression(param, context);
            LIST_AddString(&newContext.params, value);
            newContext.paramNumber++;
            param = param->next;
        }
    }

    if (luaMethod.type == V_UI_NODEMETHOD_LUA) {
        UI_ExecuteLuaMethod(callNode, luaMethod.ofs, newContext.params, newContext.paramNumber);
        Mem_Free(const_cast<char*>(luaMethod.string));
    }
    else if (callProperty == nullptr || callProperty->type == V_UI_ACTION) {
        uiAction_t const* const actionsRef = callProperty ? Com_GetValue<uiAction_t*>(callNode, callProperty) : callNode->onClick;
        if (actionsRef)
            UI_ExecuteActions(actionsRef, &newContext);
        if (callNode->lua_onClick != LUA_NOREF)
            UI_ExecuteLuaMethod(callNode, callNode->lua_onClick, newContext.params, newContext.paramNumber);
    }
    else if (callProperty->type == V_UI_NODEMETHOD) {
        uiNodeMethod_t func = (uiNodeMethod_t) callProperty->ofs;
        func(callNode, &newContext);
    }
    else {
        /* unreachable, already checked few line before */
        assert(false);
    }

    LIST_Delete(&newContext.params);
}