mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
28 Commits
ai-ux-impr
...
Expression
Author | SHA1 | Date | |
---|---|---|---|
![]() |
55fc686a5b | ||
![]() |
5580189f88 | ||
![]() |
9a6d1d6d32 | ||
![]() |
6c9739c01d | ||
![]() |
cd3c997b28 | ||
![]() |
8064c4de57 | ||
![]() |
8666851f54 | ||
![]() |
6d568b2f2c | ||
![]() |
180d4318aa | ||
![]() |
65a57f86da | ||
![]() |
6a3e7f9c58 | ||
![]() |
74f1d571ba | ||
![]() |
a7cb3fc5a2 | ||
![]() |
08d3c3323a | ||
![]() |
fec603b811 | ||
![]() |
d68affc117 | ||
![]() |
77cd6c44d6 | ||
![]() |
2b4c8813e4 | ||
![]() |
2ef9266ec4 | ||
![]() |
ceba6cf739 | ||
![]() |
18f2085de7 | ||
![]() |
b586fb87ed | ||
![]() |
8aed02ab17 | ||
![]() |
8c383fc448 | ||
![]() |
af3a2016f2 | ||
![]() |
7a20161794 | ||
![]() |
0feb4ef321 | ||
![]() |
5cbcd16523 |
@@ -44,8 +44,10 @@ gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
|
||||
info.SetExtraInfo(
|
||||
// For objects/behavior, the supplementary information
|
||||
// parameter is an object/behavior type...
|
||||
(gd::ParameterMetadata::IsObject(type) ||
|
||||
((gd::ParameterMetadata::IsObject(type) ||
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
// Prefix with the namespace if it's not already there.
|
||||
&& !(supplementaryInformation.rfind(extensionNamespace, 0) == 0))
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace +
|
||||
|
@@ -222,6 +222,18 @@ class GD_CORE_API ExpressionMetadata {
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Set the additional information, used for some parameters
|
||||
* with special type (for example, it can contains the type of object accepted
|
||||
* by the parameter), for the last added parameter.
|
||||
*
|
||||
* \see AddParameter
|
||||
*/
|
||||
ExpressionMetadata &SetParameterExtraInfo(const gd::String &extraInfo) {
|
||||
if (!parameters.empty()) parameters.back().SetExtraInfo(extraInfo);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Mark this (object) expression as requiring the specified capability,
|
||||
* offered by the base object.
|
||||
@@ -256,7 +268,30 @@ class GD_CORE_API ExpressionMetadata {
|
||||
*/
|
||||
ExpressionCodeGenerationInformation& GetCodeExtraInformation() {
|
||||
return codeExtraInformation;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
*/
|
||||
ExpressionMetadata &SetIncludeFile(const gd::String &includeFile) {
|
||||
codeExtraInformation.SetIncludeFile(includeFile);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add a file to the already existing include files.
|
||||
*/
|
||||
ExpressionMetadata &AddIncludeFile(const gd::String &includeFile) {
|
||||
codeExtraInformation.AddIncludeFile(includeFile);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the files that must be included to use the instruction.
|
||||
*/
|
||||
const std::vector<gd::String>& GetIncludeFiles() const {
|
||||
return codeExtraInformation.GetIncludeFiles();
|
||||
}
|
||||
|
||||
ExpressionCodeGenerationInformation codeExtraInformation;
|
||||
|
||||
|
@@ -62,8 +62,10 @@ InstructionMetadata& InstructionMetadata::AddParameter(
|
||||
info.SetExtraInfo(
|
||||
// For objects/behavior, the supplementary information
|
||||
// parameter is an object/behavior type...
|
||||
(gd::ParameterMetadata::IsObject(type) ||
|
||||
((gd::ParameterMetadata::IsObject(type) ||
|
||||
gd::ParameterMetadata::IsBehavior(type))
|
||||
// Prefix with the namespace if it's not already there.
|
||||
&& !(supplementaryInformation.rfind(extensionNamespace, 0) == 0))
|
||||
? (supplementaryInformation.empty()
|
||||
? ""
|
||||
: extensionNamespace +
|
||||
@@ -92,8 +94,10 @@ InstructionMetadata& InstructionMetadata::AddCodeOnlyParameter(
|
||||
}
|
||||
|
||||
InstructionMetadata& InstructionMetadata::UseStandardOperatorParameters(
|
||||
const gd::String& type) {
|
||||
SetManipulatedType(type);
|
||||
const gd::String& type, const gd::String& typeExtraInfo) {
|
||||
const gd::String& expressionValueType =
|
||||
gd::ValueTypeMetadata::GetPrimitiveValueType(type);
|
||||
SetManipulatedType(expressionValueType);
|
||||
|
||||
if (type == "boolean") {
|
||||
AddParameter("yesorno", _("New value"));
|
||||
@@ -117,8 +121,8 @@ InstructionMetadata& InstructionMetadata::UseStandardOperatorParameters(
|
||||
"_PARAM" + gd::String::From(valueParamIndex) + "_");
|
||||
}
|
||||
} else {
|
||||
AddParameter("operator", _("Modification's sign"), type);
|
||||
AddParameter(type == "number" ? "expression" : type, _("Value"));
|
||||
AddParameter("operator", _("Modification's sign"), expressionValueType);
|
||||
AddParameter(type, _("Value"), typeExtraInfo);
|
||||
|
||||
size_t operatorParamIndex = parameters.size() - 2;
|
||||
size_t valueParamIndex = parameters.size() - 1;
|
||||
@@ -151,8 +155,10 @@ InstructionMetadata& InstructionMetadata::UseStandardOperatorParameters(
|
||||
|
||||
InstructionMetadata&
|
||||
InstructionMetadata::UseStandardRelationalOperatorParameters(
|
||||
const gd::String& type) {
|
||||
SetManipulatedType(type);
|
||||
const gd::String& type, const gd::String& typeExtraInfo) {
|
||||
const gd::String& expressionValueType =
|
||||
gd::ValueTypeMetadata::GetPrimitiveValueType(type);
|
||||
SetManipulatedType(expressionValueType);
|
||||
|
||||
if (type == "boolean") {
|
||||
if (isObjectInstruction || isBehaviorInstruction) {
|
||||
@@ -168,8 +174,8 @@ InstructionMetadata::UseStandardRelationalOperatorParameters(
|
||||
templateSentence.FindAndReplace("<subject>", sentence);
|
||||
}
|
||||
} else {
|
||||
AddParameter("relationalOperator", _("Sign of the test"), type);
|
||||
AddParameter(type == "number" ? "expression" : type, _("Value to compare"));
|
||||
AddParameter("relationalOperator", _("Sign of the test"), expressionValueType);
|
||||
AddParameter(type, _("Value to compare"), typeExtraInfo);
|
||||
size_t operatorParamIndex = parameters.size() - 2;
|
||||
size_t valueParamIndex = parameters.size() - 1;
|
||||
|
||||
|
@@ -206,7 +206,7 @@ class GD_CORE_API InstructionMetadata {
|
||||
if (!parameters.empty())
|
||||
parameters.back().SetLongDescription(longDescription);
|
||||
return *this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the additional information, used for some parameters
|
||||
@@ -218,20 +218,26 @@ class GD_CORE_API InstructionMetadata {
|
||||
InstructionMetadata &SetParameterExtraInfo(const gd::String &extraInfo) {
|
||||
if (!parameters.empty()) parameters.back().SetExtraInfo(extraInfo);
|
||||
return *this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add the default parameters for an instruction manipulating the
|
||||
* specified type ("string", "number") with the default operators.
|
||||
*
|
||||
* \note The type "string" can be declined in several subtypes.
|
||||
* \see ParameterMetadata
|
||||
*/
|
||||
InstructionMetadata &UseStandardOperatorParameters(const gd::String &type);
|
||||
InstructionMetadata &UseStandardOperatorParameters(const gd::String &type, const gd::String& typeExtraInfo = "");
|
||||
|
||||
/**
|
||||
* \brief Add the default parameters for an instruction comparing the
|
||||
* specified type ("string", "number") with the default relational operators.
|
||||
*
|
||||
* \note The type "string" can be declined in several subtypes.
|
||||
* \see ParameterMetadata
|
||||
*/
|
||||
InstructionMetadata &UseStandardRelationalOperatorParameters(
|
||||
const gd::String &type);
|
||||
const gd::String &type, const gd::String& typeExtraInfo = "");
|
||||
|
||||
/**
|
||||
* \brief Mark the instruction as an object instruction. Automatically called
|
||||
@@ -276,7 +282,7 @@ class GD_CORE_API InstructionMetadata {
|
||||
*/
|
||||
const gd::String &GetRequiredBaseObjectCapability() const {
|
||||
return requiredBaseObjectCapability;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Consider that the instruction is easy for a user to understand.
|
||||
@@ -487,6 +493,29 @@ class GD_CORE_API InstructionMetadata {
|
||||
return codeExtraInformation.SetAsyncFunctionName(functionName);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Erase any existing include file and add the specified include.
|
||||
*/
|
||||
InstructionMetadata &SetIncludeFile(const gd::String &includeFile) {
|
||||
codeExtraInformation.SetIncludeFile(includeFile);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add a file to the already existing include files.
|
||||
*/
|
||||
InstructionMetadata &AddIncludeFile(const gd::String &includeFile) {
|
||||
codeExtraInformation.AddIncludeFile(includeFile);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the files that must be included to use the instruction.
|
||||
*/
|
||||
const std::vector<gd::String>& GetIncludeFiles() const {
|
||||
return codeExtraInformation.GetIncludeFiles();
|
||||
};
|
||||
|
||||
std::vector<ParameterMetadata> parameters;
|
||||
|
||||
private:
|
||||
|
@@ -80,6 +80,16 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* \see gd::InstructionMetadata::SetParameterExtraInfo
|
||||
*/
|
||||
MultipleInstructionMetadata &SetParameterExtraInfo(const gd::String &defaultValue) {
|
||||
if (expression) expression->SetParameterExtraInfo(defaultValue);
|
||||
if (condition) condition->SetParameterExtraInfo(defaultValue);
|
||||
if (action) action->SetParameterExtraInfo(defaultValue);
|
||||
return *this;
|
||||
};
|
||||
|
||||
/**
|
||||
* \see gd::InstructionMetadata::SetParameterLongDescription
|
||||
*/
|
||||
@@ -116,9 +126,9 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
* \see gd::InstructionMetadata::UseStandardOperatorParameters
|
||||
* \see gd::InstructionMetadata::UseStandardRelationalOperatorParameters
|
||||
*/
|
||||
MultipleInstructionMetadata &UseStandardParameters(const gd::String &type) {
|
||||
if (condition) condition->UseStandardRelationalOperatorParameters(type);
|
||||
if (action) action->UseStandardOperatorParameters(type);
|
||||
MultipleInstructionMetadata &UseStandardParameters(const gd::String &type, const gd::String& typeExtraInfo = "") {
|
||||
if (condition) condition->UseStandardRelationalOperatorParameters(type, typeExtraInfo);
|
||||
if (action) action->UseStandardOperatorParameters(type, typeExtraInfo);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -154,6 +164,34 @@ class GD_CORE_API MultipleInstructionMetadata {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the files that must be included to use the instruction.
|
||||
*/
|
||||
const std::vector<gd::String>& GetIncludeFiles() const {
|
||||
if (expression)
|
||||
return expression->GetCodeExtraInformation().GetIncludeFiles();
|
||||
if (condition)
|
||||
return condition->GetCodeExtraInformation().GetIncludeFiles();
|
||||
if (action)
|
||||
return action->GetCodeExtraInformation().GetIncludeFiles();
|
||||
// It can't actually happen.
|
||||
throw std::logic_error("no instruction metadata");
|
||||
}
|
||||
|
||||
/**
|
||||
* Set that the instruction is private - it can't be used outside of the
|
||||
* object/ behavior that it is attached too.
|
||||
*/
|
||||
MultipleInstructionMetadata &SetPrivate() {
|
||||
if (expression)
|
||||
expression->SetPrivate();
|
||||
if (condition)
|
||||
condition->SetPrivate();
|
||||
if (action)
|
||||
action->SetPrivate();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \see gd::InstructionMetadata::MarkAsSimple
|
||||
*/
|
||||
|
@@ -10,12 +10,10 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
ParameterMetadata::ParameterMetadata() : optional(false), codeOnly(false) {}
|
||||
ParameterMetadata::ParameterMetadata() : codeOnly(false) {}
|
||||
|
||||
void ParameterMetadata::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("type", type);
|
||||
element.SetAttribute("supplementaryInformation", supplementaryInformation);
|
||||
element.SetAttribute("optional", optional);
|
||||
valueTypeMetadata.SerializeTo(element);
|
||||
element.SetAttribute("description", description);
|
||||
element.SetAttribute("longDescription", longDescription);
|
||||
element.SetAttribute("codeOnly", codeOnly);
|
||||
@@ -24,10 +22,7 @@ void ParameterMetadata::SerializeTo(SerializerElement& element) const {
|
||||
}
|
||||
|
||||
void ParameterMetadata::UnserializeFrom(const SerializerElement& element) {
|
||||
type = element.GetStringAttribute("type");
|
||||
supplementaryInformation =
|
||||
element.GetStringAttribute("supplementaryInformation");
|
||||
optional = element.GetBoolAttribute("optional");
|
||||
valueTypeMetadata.UnserializeFrom(element);
|
||||
description = element.GetStringAttribute("description");
|
||||
longDescription = element.GetStringAttribute("longDescription");
|
||||
codeOnly = element.GetBoolAttribute("codeOnly");
|
||||
@@ -35,18 +30,4 @@ void ParameterMetadata::UnserializeFrom(const SerializerElement& element) {
|
||||
name = element.GetStringAttribute("name");
|
||||
}
|
||||
|
||||
// TODO factorize in a file with an enum and helpers?
|
||||
const gd::String ParameterMetadata::numberType = "number";
|
||||
const gd::String ParameterMetadata::stringType = "string";
|
||||
|
||||
const gd::String &ParameterMetadata::GetExpressionValueType(const gd::String ¶meterType) {
|
||||
if (parameterType == "number" || gd::ParameterMetadata::IsExpression("number", parameterType)) {
|
||||
return ParameterMetadata::numberType;
|
||||
}
|
||||
if (parameterType == "string" || gd::ParameterMetadata::IsExpression("string", parameterType)) {
|
||||
return ParameterMetadata::stringType;
|
||||
}
|
||||
return parameterType;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -6,16 +6,13 @@
|
||||
|
||||
#ifndef PARAMETER_METADATA_H
|
||||
#define PARAMETER_METADATA_H
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Extensions/Metadata/ValueTypeMetadata.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class Layout;
|
||||
class EventsCodeGenerator;
|
||||
class EventsCodeGenerationContext;
|
||||
class SerializerElement;
|
||||
} // namespace gd
|
||||
|
||||
@@ -32,17 +29,32 @@ class GD_CORE_API ParameterMetadata {
|
||||
ParameterMetadata();
|
||||
virtual ~ParameterMetadata(){};
|
||||
|
||||
/**
|
||||
* \brief Return the metadata of the parameter type.
|
||||
*/
|
||||
gd::ValueTypeMetadata &GetValueTypeMetadata() { return valueTypeMetadata; }
|
||||
|
||||
/**
|
||||
* \brief Set the metadata of the parameter type.
|
||||
*/
|
||||
ParameterMetadata &SetValueTypeMetadata(const gd::ValueTypeMetadata &valueTypeMetadata_) {
|
||||
valueTypeMetadata = valueTypeMetadata_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the type of the parameter.
|
||||
* \see gd::ParameterMetadata::IsObject
|
||||
* \deprecated Use gd::ValueTypeMetadata instead.
|
||||
*/
|
||||
const gd::String &GetType() const { return type; }
|
||||
const gd::String &GetType() const { return valueTypeMetadata.GetName(); }
|
||||
|
||||
/**
|
||||
* \brief Set the type of the parameter.
|
||||
* \deprecated Use gd::ValueTypeMetadata instead.
|
||||
*/
|
||||
ParameterMetadata &SetType(const gd::String &type_) {
|
||||
type = type_;
|
||||
valueTypeMetadata.SetName(type_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -71,29 +83,33 @@ class GD_CORE_API ParameterMetadata {
|
||||
* \brief Return an optional additional information, used for some parameters
|
||||
* with special type (for example, it can contains the type of object accepted
|
||||
* by the parameter).
|
||||
* \deprecated Use gd::ValueTypeMetadata instead.
|
||||
*/
|
||||
const gd::String &GetExtraInfo() const { return supplementaryInformation; }
|
||||
const gd::String &GetExtraInfo() const { return valueTypeMetadata.GetExtraInfo(); }
|
||||
|
||||
/**
|
||||
* \brief Set an optional additional information, used for some parameters
|
||||
* with special type (for example, it can contains the type of object accepted
|
||||
* by the parameter).
|
||||
* \deprecated Use gd::ValueTypeMetadata instead.
|
||||
*/
|
||||
ParameterMetadata &SetExtraInfo(const gd::String &supplementaryInformation_) {
|
||||
supplementaryInformation = supplementaryInformation_;
|
||||
valueTypeMetadata.SetExtraInfo(supplementaryInformation_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the parameter is optional.
|
||||
* \deprecated Use gd::ValueTypeMetadata instead.
|
||||
*/
|
||||
bool IsOptional() const { return optional; }
|
||||
bool IsOptional() const { return valueTypeMetadata.IsOptional(); }
|
||||
|
||||
/**
|
||||
* \brief Set if the parameter is optional.
|
||||
* \deprecated Use gd::ValueTypeMetadata instead.
|
||||
*/
|
||||
ParameterMetadata &SetOptional(bool optional_ = true) {
|
||||
optional = optional_;
|
||||
valueTypeMetadata.SetOptional(optional_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -151,26 +167,27 @@ class GD_CORE_API ParameterMetadata {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO Remove these deprecated functions.
|
||||
|
||||
/**
|
||||
* \brief Return true if the type of the parameter is representing one object
|
||||
* (or more, i.e: an object group).
|
||||
*
|
||||
* \see gd::ParameterMetadata::GetType
|
||||
* \deprecated Use gd::ValueTypeMetadata instead.
|
||||
*/
|
||||
static bool IsObject(const gd::String ¶meterType) {
|
||||
return parameterType == "object" || parameterType == "objectPtr" ||
|
||||
parameterType == "objectList" ||
|
||||
parameterType == "objectListOrEmptyIfJustDeclared" ||
|
||||
parameterType == "objectListOrEmptyWithoutPicking";
|
||||
return gd::ValueTypeMetadata::IsTypeObject(parameterType);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type of the parameter is "behavior".
|
||||
*
|
||||
* \see gd::ParameterMetadata::GetType
|
||||
* \deprecated Use gd::ValueTypeMetadata instead.
|
||||
*/
|
||||
static bool IsBehavior(const gd::String ¶meterType) {
|
||||
return parameterType == "behavior";
|
||||
return gd::ValueTypeMetadata::IsTypeBehavior(parameterType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -179,43 +196,22 @@ class GD_CORE_API ParameterMetadata {
|
||||
* \note If you had a new type of parameter, also add it in the IDE (
|
||||
* see EventsFunctionParametersEditor, ParameterRenderingService
|
||||
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
|
||||
* \deprecated Use gd::ValueTypeMetadata instead.
|
||||
*/
|
||||
static bool IsExpression(const gd::String &type,
|
||||
const gd::String ¶meterType) {
|
||||
if (type == "number") {
|
||||
return parameterType == "expression" || parameterType == "camera" ||
|
||||
parameterType == "forceMultiplier";
|
||||
} else if (type == "string") {
|
||||
return parameterType == "string" || parameterType == "layer" ||
|
||||
parameterType == "color" || parameterType == "file" ||
|
||||
parameterType == "joyaxis" ||
|
||||
parameterType == "stringWithSelector" ||
|
||||
parameterType == "sceneName" ||
|
||||
parameterType == "layerEffectName" ||
|
||||
parameterType == "layerEffectParameterName" ||
|
||||
parameterType == "objectEffectName" ||
|
||||
parameterType == "objectEffectParameterName" ||
|
||||
parameterType == "objectPointName" ||
|
||||
parameterType == "objectAnimationName" ||
|
||||
parameterType == "functionParameterName" ||
|
||||
parameterType == "externalLayoutName" ||
|
||||
parameterType == "leaderboardId" ||
|
||||
parameterType == "identifier";
|
||||
} else if (type == "variable") {
|
||||
return parameterType == "objectvar" || parameterType == "globalvar" ||
|
||||
parameterType == "scenevar";
|
||||
}
|
||||
return false;
|
||||
return gd::ValueTypeMetadata::IsTypeExpression(type, parameterType);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the expression type from the parameter type.
|
||||
* Declinations of "number" and "string" types (like "forceMultiplier" or
|
||||
* "sceneName") are replaced by "number" and "string".
|
||||
* \deprecated Use gd::ValueTypeMetadata instead.
|
||||
*/
|
||||
static const gd::String &GetExpressionValueType(const gd::String ¶meterType);
|
||||
static const gd::String numberType;
|
||||
static const gd::String stringType;
|
||||
static const gd::String &GetExpressionValueType(const gd::String ¶meterType) {
|
||||
return gd::ValueTypeMetadata::GetPrimitiveValueType(parameterType);
|
||||
}
|
||||
|
||||
/** \name Serialization
|
||||
*/
|
||||
@@ -238,9 +234,7 @@ class GD_CORE_API ParameterMetadata {
|
||||
bool codeOnly; ///< True if parameter is relative to code generation only,
|
||||
///< i.e. must not be shown in editor
|
||||
private:
|
||||
gd::String type; ///< Parameter type
|
||||
gd::String supplementaryInformation; ///< Used if needed
|
||||
bool optional; ///< True if the parameter is optional
|
||||
gd::ValueTypeMetadata valueTypeMetadata; ///< Parameter type
|
||||
gd::String longDescription; ///< Long description shown in the editor.
|
||||
gd::String defaultValue; ///< Used as a default value in editor or if an
|
||||
///< optional parameter is empty.
|
||||
@@ -250,5 +244,4 @@ class GD_CORE_API ParameterMetadata {
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
||||
#endif // PARAMETER_METADATA_H
|
||||
|
49
Core/GDCore/Extensions/Metadata/ValueTypeMetadata.cpp
Normal file
49
Core/GDCore/Extensions/Metadata/ValueTypeMetadata.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ValueTypeMetadata.h"
|
||||
|
||||
#include "GDCore/CommonTools.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
ValueTypeMetadata::ValueTypeMetadata() : optional(false) {}
|
||||
|
||||
void ValueTypeMetadata::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("type", name);
|
||||
if (!supplementaryInformation.empty()) {
|
||||
element.SetAttribute("supplementaryInformation", supplementaryInformation);
|
||||
}
|
||||
if (optional) {
|
||||
element.SetAttribute("optional", optional);
|
||||
}
|
||||
if (!defaultValue.empty()) {
|
||||
element.SetAttribute("defaultValue", defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
void ValueTypeMetadata::UnserializeFrom(const SerializerElement& element) {
|
||||
name = element.GetStringAttribute("type");
|
||||
supplementaryInformation =
|
||||
element.GetStringAttribute("supplementaryInformation");
|
||||
optional = element.GetBoolAttribute("optional");
|
||||
defaultValue = element.GetStringAttribute("defaultValue");
|
||||
}
|
||||
|
||||
const gd::String ValueTypeMetadata::numberType = "number";
|
||||
const gd::String ValueTypeMetadata::stringType = "string";
|
||||
|
||||
const gd::String &ValueTypeMetadata::GetPrimitiveValueType(const gd::String ¶meterType) {
|
||||
if (parameterType == "number" || gd::ValueTypeMetadata::IsTypeExpression("number", parameterType)) {
|
||||
return ValueTypeMetadata::numberType;
|
||||
}
|
||||
if (parameterType == "string" || gd::ValueTypeMetadata::IsTypeExpression("string", parameterType)) {
|
||||
return ValueTypeMetadata::stringType;
|
||||
}
|
||||
return parameterType;
|
||||
}
|
||||
|
||||
} // namespace gd
|
219
Core/GDCore/Extensions/Metadata/ValueTypeMetadata.h
Normal file
219
Core/GDCore/Extensions/Metadata/ValueTypeMetadata.h
Normal file
@@ -0,0 +1,219 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef VALUE_TYPE_METADATA_H
|
||||
#define VALUE_TYPE_METADATA_H
|
||||
#include <map>
|
||||
#include <memory>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Define a type for parameters of a function (action, condition or
|
||||
* expression) or the returned value of an expression.
|
||||
*
|
||||
* \see gd::EventsFunction
|
||||
* \ingroup Events
|
||||
*/
|
||||
class GD_CORE_API ValueTypeMetadata {
|
||||
public:
|
||||
ValueTypeMetadata();
|
||||
virtual ~ValueTypeMetadata(){};
|
||||
|
||||
/**
|
||||
* \brief Return the string representation of the type.
|
||||
*/
|
||||
const gd::String &GetName() const { return name; }
|
||||
|
||||
/**
|
||||
* \brief Set the string representation of the type.
|
||||
*/
|
||||
ValueTypeMetadata &SetName(const gd::String &name_) {
|
||||
name = name_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return an optional additional information, used for some parameters
|
||||
* with special type (for example, it can contains the type of object accepted
|
||||
* by the parameter).
|
||||
*/
|
||||
const gd::String &GetExtraInfo() const { return supplementaryInformation; }
|
||||
|
||||
/**
|
||||
* \brief Set an optional additional information, used for some parameters
|
||||
* with special type (for example, it can contains the type of object accepted
|
||||
* by the parameter).
|
||||
*/
|
||||
ValueTypeMetadata &SetExtraInfo(const gd::String &supplementaryInformation_) {
|
||||
supplementaryInformation = supplementaryInformation_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the parameter is optional.
|
||||
*/
|
||||
bool IsOptional() const { return optional; }
|
||||
|
||||
/**
|
||||
* \brief Set if the parameter is optional.
|
||||
*/
|
||||
ValueTypeMetadata &SetOptional(bool optional_ = true) {
|
||||
optional = optional_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the default value for the parameter.
|
||||
*/
|
||||
const gd::String &GetDefaultValue() const { return defaultValue; }
|
||||
|
||||
/**
|
||||
* \brief Set the default value, if the parameter is optional.
|
||||
*/
|
||||
ValueTypeMetadata &SetDefaultValue(const gd::String &defaultValue_) {
|
||||
defaultValue = defaultValue_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is defined.
|
||||
*/
|
||||
bool IsDefined() const {
|
||||
return !name.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is representing one object
|
||||
* (or more, i.e: an object group).
|
||||
*/
|
||||
bool IsObject() const {
|
||||
return gd::ValueTypeMetadata::IsTypeObject(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is "behavior".
|
||||
*/
|
||||
bool IsBehavior() const {
|
||||
return gd::ValueTypeMetadata::IsTypeBehavior(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is an expression of the
|
||||
* given type.
|
||||
*/
|
||||
bool IsNumber() const {
|
||||
return gd::ValueTypeMetadata::IsTypeExpression("number", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is a string.
|
||||
*/
|
||||
bool IsString() const {
|
||||
return gd::ValueTypeMetadata::IsTypeExpression("string", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type of the parameter is a number.
|
||||
* \note If you had a new type of parameter, also add it in the IDE (
|
||||
* see EventsFunctionParametersEditor, ParameterRenderingService
|
||||
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
|
||||
*/
|
||||
bool IsVariable() const {
|
||||
return gd::ValueTypeMetadata::IsTypeExpression("variable", name);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is representing one object
|
||||
* (or more, i.e: an object group).
|
||||
*/
|
||||
static bool IsTypeObject(const gd::String ¶meterType) {
|
||||
return parameterType == "object" || parameterType == "objectPtr" ||
|
||||
parameterType == "objectList" ||
|
||||
parameterType == "objectListOrEmptyIfJustDeclared" ||
|
||||
parameterType == "objectListOrEmptyWithoutPicking";
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is "behavior".
|
||||
*/
|
||||
static bool IsTypeBehavior(const gd::String ¶meterType) {
|
||||
return parameterType == "behavior";
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the type is an expression of the given type.
|
||||
* \note If you are adding a new type of parameter, also add it in the IDE (
|
||||
* see EventsFunctionParametersEditor, ParameterRenderingService
|
||||
* and ExpressionAutocompletion) and in the EventsCodeGenerator.
|
||||
*/
|
||||
static bool IsTypeExpression(const gd::String &type,
|
||||
const gd::String ¶meterType) {
|
||||
if (type == "number") {
|
||||
return parameterType == "number" || parameterType == "expression" ||
|
||||
parameterType == "camera" || parameterType == "forceMultiplier";
|
||||
} else if (type == "string") {
|
||||
return parameterType == "string" || parameterType == "layer" ||
|
||||
parameterType == "color" || parameterType == "file" ||
|
||||
parameterType == "joyaxis" ||
|
||||
parameterType == "stringWithSelector" ||
|
||||
parameterType == "sceneName" ||
|
||||
parameterType == "layerEffectName" ||
|
||||
parameterType == "layerEffectParameterName" ||
|
||||
parameterType == "objectEffectName" ||
|
||||
parameterType == "objectEffectParameterName" ||
|
||||
parameterType == "objectPointName" ||
|
||||
parameterType == "objectAnimationName" ||
|
||||
parameterType == "functionParameterName" ||
|
||||
parameterType == "externalLayoutName" ||
|
||||
parameterType == "leaderboardId" ||
|
||||
parameterType == "identifier";
|
||||
} else if (type == "variable") {
|
||||
return parameterType == "objectvar" || parameterType == "globalvar" ||
|
||||
parameterType == "scenevar";
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the expression type from the parameter type.
|
||||
* Declinations of "number" and "string" types (like "forceMultiplier" or
|
||||
* "sceneName") are replaced by "number" and "string".
|
||||
*/
|
||||
static const gd::String &GetPrimitiveValueType(const gd::String ¶meterType);
|
||||
static const gd::String numberType;
|
||||
static const gd::String stringType;
|
||||
|
||||
/** \name Serialization
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Serialize the ParameterMetadata to the specified element
|
||||
*/
|
||||
void SerializeTo(gd::SerializerElement &element) const;
|
||||
|
||||
/**
|
||||
* \brief Load the ParameterMetadata from the specified element
|
||||
*/
|
||||
void UnserializeFrom(const gd::SerializerElement &element);
|
||||
///@}
|
||||
|
||||
private:
|
||||
gd::String name; ///< Parameter type
|
||||
gd::String supplementaryInformation; ///< Used if needed
|
||||
bool optional; ///< True if the parameter is optional
|
||||
gd::String defaultValue; ///< Used as a default value in editor or if an
|
||||
///< optional parameter is empty.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // VALUE_TYPE_METADATA_H
|
@@ -20,6 +20,7 @@ namespace gd {
|
||||
|
||||
void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsFunctionsContainer functionContainer,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
@@ -31,8 +32,12 @@ void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
// to parameters
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
outputObjectsContainer.GetObjectGroups().Clear();
|
||||
|
||||
auto ¶meters = eventsFunction.GetParametersForEvents(functionContainer);
|
||||
gd::ParameterMetadataTools::ParametersToObjectsContainer(
|
||||
project, eventsFunction.GetParameters(), outputObjectsContainer);
|
||||
project,
|
||||
parameters,
|
||||
outputObjectsContainer);
|
||||
outputObjectsContainer.GetObjectGroups() = eventsFunction.GetObjectGroups();
|
||||
}
|
||||
|
||||
@@ -44,6 +49,7 @@ void EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// The context is build the same way as free function...
|
||||
FreeEventsFunctionToObjectsContainer(project,
|
||||
eventsBasedBehavior.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
outputGlobalObjectsContainer,
|
||||
outputObjectsContainer);
|
||||
@@ -81,6 +87,7 @@ void EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// The context is build the same way as free function...
|
||||
FreeEventsFunctionToObjectsContainer(project,
|
||||
eventsBasedObject.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
outputGlobalObjectsContainer,
|
||||
outputObjectsContainer);
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class Project;
|
||||
class EventsFunctionsContainer;
|
||||
class ObjectsContainer;
|
||||
class ParameterMetadata;
|
||||
class EventsFunction;
|
||||
@@ -34,6 +35,7 @@ class GD_CORE_API EventsFunctionTools {
|
||||
*/
|
||||
static void FreeEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsFunctionsContainer functionContainer,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
|
@@ -154,7 +154,11 @@ void WholeProjectRefactorer::ExposeProjectEvents(
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
project, *eventsFunction, globalObjectsAndGroups, objectsAndGroups);
|
||||
project,
|
||||
eventsFunctionsExtension,
|
||||
*eventsFunction,
|
||||
globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(),
|
||||
globalObjectsAndGroups,
|
||||
@@ -334,8 +338,10 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
[&project, &oldName, &newName](
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction) {
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
// Nothing to do, expressions are not including the extension name
|
||||
}
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
GetBehaviorEventsFunctionFullType(oldName,
|
||||
@@ -345,11 +351,6 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
eventsBasedBehavior.GetName(),
|
||||
eventsFunction.GetName()));
|
||||
ExposeProjectEvents(project, renamer);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
// Nothing to do, expressions are not including the extension name
|
||||
}
|
||||
};
|
||||
|
||||
@@ -394,8 +395,10 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
[&project, &oldName, &newName](
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction) {
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
// Nothing to do, expressions are not including the extension name
|
||||
}
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
GetObjectEventsFunctionFullType(oldName,
|
||||
@@ -405,11 +408,6 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
eventsBasedObject.GetName(),
|
||||
eventsFunction.GetName()));
|
||||
ExposeProjectEvents(project, renamer);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
// Nothing to do, expressions are not including the extension name
|
||||
}
|
||||
};
|
||||
|
||||
@@ -456,9 +454,7 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
|
||||
// Free expressions
|
||||
for (auto&& eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Expression ||
|
||||
eventsFunction->GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
if (eventsFunction->IsExpression()) {
|
||||
renameEventsFunction(*eventsFunction);
|
||||
}
|
||||
}
|
||||
@@ -467,9 +463,7 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
eventsFunctionsExtension.GetEventsBasedBehaviors().GetInternalVector()) {
|
||||
auto& behaviorEventsFunctions = eventsBasedBehavior->GetEventsFunctions();
|
||||
for (auto&& eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
|
||||
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Expression ||
|
||||
eventsFunction->GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
if (eventsFunction->IsExpression()) {
|
||||
renameBehaviorEventsFunction(*eventsBasedBehavior, *eventsFunction);
|
||||
}
|
||||
}
|
||||
@@ -477,8 +471,7 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
|
||||
// Free instructions
|
||||
for (auto&& eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction->GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
if (eventsFunction->IsAction() || eventsFunction->IsCondition()) {
|
||||
renameEventsFunction(*eventsFunction);
|
||||
}
|
||||
}
|
||||
@@ -488,8 +481,7 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
eventsFunctionsExtension.GetEventsBasedBehaviors().GetInternalVector()) {
|
||||
auto& behaviorEventsFunctions = eventsBasedBehavior->GetEventsFunctions();
|
||||
for (auto&& eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
|
||||
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction->GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
if (eventsFunction->IsAction() || eventsFunction->IsCondition()) {
|
||||
renameBehaviorEventsFunction(*eventsBasedBehavior, *eventsFunction);
|
||||
}
|
||||
}
|
||||
@@ -510,8 +502,7 @@ void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
|
||||
auto& objectEventsFunctions = eventsBasedObject->GetEventsFunctions();
|
||||
for (auto&& eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction->GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
if (eventsFunction->IsAction() || eventsFunction->IsCondition()) {
|
||||
renameObjectEventsFunction(*eventsBasedObject, *eventsFunction);
|
||||
}
|
||||
}
|
||||
@@ -563,6 +554,16 @@ void WholeProjectRefactorer::RenameEventsFunction(
|
||||
oldFunctionName),
|
||||
GetEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
newFunctionName));
|
||||
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::ExpressionAndCondition) {
|
||||
for (auto&& otherFunction : eventsFunctionsExtension.GetInternalVector())
|
||||
{
|
||||
if (otherFunction->GetFunctionType() == gd::EventsFunction::ActionWithOperator &&
|
||||
otherFunction->GetGetterName() == oldFunctionName) {
|
||||
otherFunction->SetGetterName(newFunctionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameBehaviorEventsFunction(
|
||||
@@ -577,8 +578,20 @@ void WholeProjectRefactorer::RenameBehaviorEventsFunction(
|
||||
const gd::EventsFunction& eventsFunction =
|
||||
eventsFunctions.GetEventsFunction(oldFunctionName);
|
||||
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
// Order is important: we first rename the expressions then the instructions,
|
||||
// to avoid being unable to fetch the metadata (the types of parameters) of
|
||||
// instructions after they are renamed.
|
||||
if (eventsFunction.IsExpression()) {
|
||||
gd::ExpressionsRenamer renamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
renamer.SetReplacedBehaviorExpression(
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()),
|
||||
oldFunctionName,
|
||||
newFunctionName);
|
||||
ExposeProjectEvents(project, renamer);
|
||||
}
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
GetBehaviorEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
@@ -588,18 +601,15 @@ void WholeProjectRefactorer::RenameBehaviorEventsFunction(
|
||||
eventsBasedBehavior.GetName(),
|
||||
newFunctionName));
|
||||
ExposeProjectEvents(project, renamer);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
gd::ExpressionsRenamer renamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
renamer.SetReplacedBehaviorExpression(
|
||||
GetBehaviorFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedBehavior.GetName()),
|
||||
oldFunctionName,
|
||||
newFunctionName);
|
||||
ExposeProjectEvents(project, renamer);
|
||||
}
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::ExpressionAndCondition) {
|
||||
for (auto&& otherFunction : eventsBasedBehavior.GetEventsFunctions().GetInternalVector())
|
||||
{
|
||||
if (otherFunction->GetFunctionType() == gd::EventsFunction::ActionWithOperator &&
|
||||
otherFunction->GetGetterName() == oldFunctionName) {
|
||||
otherFunction->SetGetterName(newFunctionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -615,8 +625,17 @@ void WholeProjectRefactorer::RenameObjectEventsFunction(
|
||||
const gd::EventsFunction& eventsFunction =
|
||||
eventsFunctions.GetEventsFunction(oldFunctionName);
|
||||
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
gd::ExpressionsRenamer renamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
renamer.SetReplacedObjectExpression(
|
||||
GetObjectFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName()),
|
||||
oldFunctionName,
|
||||
newFunctionName);
|
||||
ExposeProjectEvents(project, renamer);
|
||||
}
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
GetObjectEventsFunctionFullType(eventsFunctionsExtension.GetName(),
|
||||
@@ -626,18 +645,15 @@ void WholeProjectRefactorer::RenameObjectEventsFunction(
|
||||
eventsBasedObject.GetName(),
|
||||
newFunctionName));
|
||||
ExposeProjectEvents(project, renamer);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
gd::ExpressionsRenamer renamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
renamer.SetReplacedObjectExpression(
|
||||
GetObjectFullType(eventsFunctionsExtension.GetName(),
|
||||
eventsBasedObject.GetName()),
|
||||
oldFunctionName,
|
||||
newFunctionName);
|
||||
ExposeProjectEvents(project, renamer);
|
||||
}
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::ExpressionAndCondition) {
|
||||
for (auto&& otherFunction : eventsBasedObject.GetEventsFunctions().GetInternalVector())
|
||||
{
|
||||
if (otherFunction->GetFunctionType() == gd::EventsFunction::ActionWithOperator &&
|
||||
otherFunction->GetGetterName() == oldFunctionName) {
|
||||
otherFunction->SetGetterName(newFunctionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,21 +671,22 @@ void WholeProjectRefactorer::MoveEventsFunctionParameter(
|
||||
const gd::String& eventsFunctionType = GetEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), functionName);
|
||||
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
gd::InstructionsParameterMover mover = gd::InstructionsParameterMover(
|
||||
project, eventsFunctionType, oldIndex, newIndex);
|
||||
ExposeProjectEvents(project, mover);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
gd::ExpressionsParameterMover mover =
|
||||
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
|
||||
mover.SetFreeExpressionMovedParameter(
|
||||
eventsFunctionType, oldIndex, newIndex);
|
||||
ExposeProjectEvents(project, mover);
|
||||
}
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
const int operatorIndexOffset = eventsFunction.IsExpression() ? 2 : 0;
|
||||
gd::InstructionsParameterMover mover = gd::InstructionsParameterMover(
|
||||
project,
|
||||
eventsFunctionType,
|
||||
oldIndex + operatorIndexOffset,
|
||||
newIndex + operatorIndexOffset);
|
||||
ExposeProjectEvents(project, mover);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
|
||||
@@ -690,15 +707,7 @@ void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
|
||||
eventsBasedBehavior.GetName(),
|
||||
functionName);
|
||||
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
gd::InstructionsParameterMover mover = gd::InstructionsParameterMover(
|
||||
project, eventsFunctionType, oldIndex, newIndex);
|
||||
ExposeProjectEvents(project, mover);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
gd::ExpressionsParameterMover mover =
|
||||
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
|
||||
mover.SetBehaviorExpressionMovedParameter(
|
||||
@@ -709,6 +718,15 @@ void WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
|
||||
newIndex);
|
||||
ExposeProjectEvents(project, mover);
|
||||
}
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
const int operatorIndexOffset = eventsFunction.IsExpression() ? 2 : 0;
|
||||
gd::InstructionsParameterMover mover = gd::InstructionsParameterMover(
|
||||
project,
|
||||
eventsFunctionType,
|
||||
oldIndex + operatorIndexOffset,
|
||||
newIndex + operatorIndexOffset);
|
||||
ExposeProjectEvents(project, mover);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::MoveObjectEventsFunctionParameter(
|
||||
@@ -729,15 +747,7 @@ void WholeProjectRefactorer::MoveObjectEventsFunctionParameter(
|
||||
eventsBasedObject.GetName(),
|
||||
functionName);
|
||||
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
gd::InstructionsParameterMover mover = gd::InstructionsParameterMover(
|
||||
project, eventsFunctionType, oldIndex, newIndex);
|
||||
ExposeProjectEvents(project, mover);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
gd::ExpressionsParameterMover mover =
|
||||
gd::ExpressionsParameterMover(project.GetCurrentPlatform());
|
||||
mover.SetObjectExpressionMovedParameter(
|
||||
@@ -748,6 +758,15 @@ void WholeProjectRefactorer::MoveObjectEventsFunctionParameter(
|
||||
newIndex);
|
||||
ExposeProjectEvents(project, mover);
|
||||
}
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
const int operatorIndexOffset = eventsFunction.IsExpression() ? 2 : 0;
|
||||
gd::InstructionsParameterMover mover = gd::InstructionsParameterMover(
|
||||
project,
|
||||
eventsFunctionType,
|
||||
oldIndex + operatorIndexOffset,
|
||||
newIndex + operatorIndexOffset);
|
||||
ExposeProjectEvents(project, mover);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
@@ -1088,8 +1107,11 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
&eventsFunctionsExtension,
|
||||
&oldBehaviorName,
|
||||
&newBehaviorName](const gd::EventsFunction& eventsFunction) {
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
// Nothing to do, expressions are not including the name of the
|
||||
// behavior
|
||||
}
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
GetBehaviorEventsFunctionFullType(
|
||||
@@ -1101,12 +1123,6 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
newBehaviorName,
|
||||
eventsFunction.GetName()));
|
||||
ExposeProjectEvents(project, renamer);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
// Nothing to do, expressions are not including the name of the
|
||||
// behavior
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1151,17 +1167,14 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
|
||||
// Behavior expressions
|
||||
for (auto&& eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
|
||||
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Expression ||
|
||||
eventsFunction->GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
if (eventsFunction->IsExpression()) {
|
||||
renameBehaviorEventsFunction(*eventsFunction);
|
||||
}
|
||||
}
|
||||
|
||||
// Behavior instructions
|
||||
for (auto&& eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
|
||||
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction->GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
if (eventsFunction->IsAction() || eventsFunction->IsCondition()) {
|
||||
renameBehaviorEventsFunction(*eventsFunction);
|
||||
}
|
||||
}
|
||||
@@ -1197,8 +1210,11 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
&eventsFunctionsExtension,
|
||||
&oldObjectName,
|
||||
&newObjectName](const gd::EventsFunction& eventsFunction) {
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
// Nothing to do, expressions are not including the name of the
|
||||
// object
|
||||
}
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
GetObjectEventsFunctionFullType(
|
||||
@@ -1210,12 +1226,6 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
newObjectName,
|
||||
eventsFunction.GetName()));
|
||||
ExposeProjectEvents(project, renamer);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
// Nothing to do, expressions are not including the name of the
|
||||
// object
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1260,17 +1270,14 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
|
||||
// Object expressions
|
||||
for (auto&& eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Expression ||
|
||||
eventsFunction->GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
if (eventsFunction->IsExpression()) {
|
||||
renameObjectEventsFunction(*eventsFunction);
|
||||
}
|
||||
}
|
||||
|
||||
// Object instructions
|
||||
for (auto&& eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
if (eventsFunction->GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction->GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
if (eventsFunction->IsAction() || eventsFunction->IsCondition()) {
|
||||
renameObjectEventsFunction(*eventsFunction);
|
||||
}
|
||||
}
|
||||
@@ -1292,20 +1299,20 @@ void WholeProjectRefactorer::DoRenameEventsFunction(
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& oldFullType,
|
||||
const gd::String& newFullType) {
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Action ||
|
||||
eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
gd::InstructionsTypeRenamer renamer =
|
||||
gd::InstructionsTypeRenamer(project, oldFullType, newFullType);
|
||||
ExposeProjectEvents(project, renamer);
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression ||
|
||||
eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
// Order is important: we first rename the expressions then the instructions,
|
||||
// to avoid being unable to fetch the metadata (the types of parameters) of
|
||||
// instructions after they are renamed.
|
||||
if (eventsFunction.IsExpression()) {
|
||||
gd::ExpressionsRenamer renamer =
|
||||
gd::ExpressionsRenamer(project.GetCurrentPlatform());
|
||||
renamer.SetReplacedFreeExpression(oldFullType, newFullType);
|
||||
ExposeProjectEvents(project, renamer);
|
||||
}
|
||||
if (eventsFunction.IsAction() || eventsFunction.IsCondition()) {
|
||||
gd::InstructionsTypeRenamer renamer =
|
||||
gd::InstructionsTypeRenamer(project, oldFullType, newFullType);
|
||||
ExposeProjectEvents(project, renamer);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::DoRenameBehavior(
|
||||
|
@@ -10,8 +10,10 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
AbstractEventsBasedEntity::AbstractEventsBasedEntity(const gd::String& _name)
|
||||
: name(_name), fullName("") {}
|
||||
AbstractEventsBasedEntity::AbstractEventsBasedEntity(
|
||||
const gd::String& _name,
|
||||
gd::EventsFunctionsContainer::FunctionOwner functionContainerSource)
|
||||
: name(_name), fullName(""), eventsFunctionsContainer(functionContainerSource) {}
|
||||
|
||||
void AbstractEventsBasedEntity::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("description", description);
|
||||
|
@@ -29,7 +29,9 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API AbstractEventsBasedEntity {
|
||||
public:
|
||||
AbstractEventsBasedEntity(const gd::String& _name);
|
||||
AbstractEventsBasedEntity(
|
||||
const gd::String& _name,
|
||||
gd::EventsFunctionsContainer::FunctionOwner functionContainerSource);
|
||||
virtual ~AbstractEventsBasedEntity(){};
|
||||
|
||||
/**
|
||||
|
@@ -11,7 +11,9 @@
|
||||
namespace gd {
|
||||
|
||||
EventsBasedBehavior::EventsBasedBehavior()
|
||||
: AbstractEventsBasedEntity("MyBehavior") {}
|
||||
: AbstractEventsBasedEntity(
|
||||
"MyBehavior",
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Behavior) {}
|
||||
|
||||
void EventsBasedBehavior::SerializeTo(SerializerElement& element) const {
|
||||
AbstractEventsBasedEntity::SerializeTo(element);
|
||||
|
@@ -10,7 +10,10 @@
|
||||
namespace gd {
|
||||
|
||||
EventsBasedObject::EventsBasedObject()
|
||||
: AbstractEventsBasedEntity("MyObject"), ObjectsContainer() {
|
||||
: AbstractEventsBasedEntity(
|
||||
"MyObject",
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Object),
|
||||
ObjectsContainer() {
|
||||
}
|
||||
|
||||
EventsBasedObject::~EventsBasedObject() {}
|
||||
|
@@ -7,10 +7,54 @@
|
||||
#include "EventsFunction.h"
|
||||
#include <vector>
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Project/EventsFunctionsContainer.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
EventsFunction::EventsFunction() : functionType(Action) {}
|
||||
EventsFunction::EventsFunction() : functionType(Action) {
|
||||
expressionType.SetName("expression");
|
||||
}
|
||||
|
||||
const std::vector<gd::ParameterMetadata>& EventsFunction::GetParametersForEvents(
|
||||
const gd::EventsFunctionsContainer& functionsContainer) const {
|
||||
if (functionType != FunctionType::ActionWithOperator) {
|
||||
// For most function types, the parameters are specified in the function.
|
||||
return parameters;
|
||||
}
|
||||
// For ActionWithOperator, the parameters are auto generated.
|
||||
actionWithOperationParameters.clear();
|
||||
if (!functionsContainer.HasEventsFunctionNamed(getterName)) {
|
||||
return actionWithOperationParameters;
|
||||
}
|
||||
const auto& expression = functionsContainer.GetEventsFunction(getterName);
|
||||
const auto& expressionParameters = expression.parameters;
|
||||
const auto functionsSource = functionsContainer.GetOwner();
|
||||
const int expressionValueParameterIndex =
|
||||
functionsSource == gd::EventsFunctionsContainer::FunctionOwner::Behavior ?
|
||||
2 :
|
||||
functionsSource == gd::EventsFunctionsContainer::FunctionOwner::Object ?
|
||||
1 :
|
||||
0;
|
||||
|
||||
for (size_t i = 0;
|
||||
i < expressionValueParameterIndex && i < expressionParameters.size();
|
||||
i++)
|
||||
{
|
||||
actionWithOperationParameters.push_back(expressionParameters[i]);
|
||||
}
|
||||
gd::ParameterMetadata parameterMetadata;
|
||||
parameterMetadata.SetName("Value").SetValueTypeMetadata(expression.expressionType);
|
||||
actionWithOperationParameters.push_back(parameterMetadata);
|
||||
for (size_t i = expressionValueParameterIndex;
|
||||
i < expressionParameters.size();
|
||||
i++)
|
||||
{
|
||||
actionWithOperationParameters.push_back(expressionParameters[i]);
|
||||
}
|
||||
|
||||
return actionWithOperationParameters;
|
||||
}
|
||||
|
||||
void EventsFunction::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", name);
|
||||
@@ -18,18 +62,33 @@ void EventsFunction::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("description", description);
|
||||
element.SetAttribute("sentence", sentence);
|
||||
element.SetAttribute("group", group);
|
||||
element.SetAttribute("getterName", getterName);
|
||||
element.SetBoolAttribute("private", isPrivate);
|
||||
events.SerializeTo(element.AddChild("events"));
|
||||
|
||||
gd::String functionTypeStr = "Action";
|
||||
if (functionType == Condition)
|
||||
functionTypeStr = "Condition";
|
||||
else if (functionType == Expression)
|
||||
else if (functionType == Expression) {
|
||||
functionTypeStr = "Expression";
|
||||
else if (functionType == StringExpression)
|
||||
functionTypeStr = "StringExpression";
|
||||
|
||||
// Compatibility code for version 5.1.147 and older.
|
||||
// There is no longer distinction between number and string in the function
|
||||
// type directly. The expression type is now used for this.
|
||||
if (expressionType.IsString()) {
|
||||
functionTypeStr = "StringExpression";
|
||||
}
|
||||
}
|
||||
else if (functionType == ExpressionAndCondition) {
|
||||
functionTypeStr = "ExpressionAndCondition";
|
||||
}
|
||||
else if (functionType == ActionWithOperator)
|
||||
functionTypeStr = "ActionWithOperator";
|
||||
element.SetAttribute("functionType", functionTypeStr);
|
||||
|
||||
if (this->IsExpression()) {
|
||||
expressionType.SerializeTo(element.AddChild("expressionType"));
|
||||
}
|
||||
gd::SerializerElement& parametersElement = element.AddChild("parameters");
|
||||
parametersElement.ConsiderAsArrayOf("parameter");
|
||||
for (const auto& parameter : parameters) {
|
||||
@@ -46,16 +105,32 @@ void EventsFunction::UnserializeFrom(gd::Project& project,
|
||||
description = element.GetStringAttribute("description");
|
||||
sentence = element.GetStringAttribute("sentence");
|
||||
group = element.GetStringAttribute("group");
|
||||
getterName = element.GetStringAttribute("getterName");
|
||||
isPrivate = element.GetBoolAttribute("private");
|
||||
events.UnserializeFrom(project, element.GetChild("events"));
|
||||
|
||||
gd::String functionTypeStr = element.GetStringAttribute("functionType");
|
||||
|
||||
if (functionTypeStr == "Condition")
|
||||
functionType = Condition;
|
||||
else if (functionTypeStr == "Expression")
|
||||
else if (functionTypeStr == "Expression" || functionTypeStr == "StringExpression") {
|
||||
functionType = Expression;
|
||||
else if (functionTypeStr == "StringExpression")
|
||||
functionType = StringExpression;
|
||||
if (element.HasChild("expressionType")) {
|
||||
expressionType.UnserializeFrom(element.GetChild("expressionType"));
|
||||
}
|
||||
else {
|
||||
// Compatibility code for version 5.1.147 and older.
|
||||
// There is no longer distinction between number and string in the function
|
||||
// type directly. The expression type is now used for this.
|
||||
expressionType.SetName(functionTypeStr == "StringExpression" ? "string" : "expression");
|
||||
}
|
||||
}
|
||||
else if (functionTypeStr == "ExpressionAndCondition") {
|
||||
functionType = ExpressionAndCondition;
|
||||
expressionType.UnserializeFrom(element.GetChild("expressionType"));
|
||||
}
|
||||
else if (functionTypeStr == "ActionWithOperator")
|
||||
functionType = ActionWithOperator;
|
||||
else
|
||||
functionType = Action;
|
||||
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Extensions/Metadata/ValueTypeMetadata.h"
|
||||
// TODO: In theory (for separation of concerns between Project and
|
||||
// extensions/events), this include should be removed and gd::ParameterMetadata
|
||||
// replaced by a new gd::EventsFunctionParameter class.
|
||||
@@ -19,6 +20,7 @@
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
class Project;
|
||||
class EventsFunctionsContainer;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -115,7 +117,40 @@ class GD_CORE_API EventsFunction {
|
||||
return *this;
|
||||
}
|
||||
|
||||
enum FunctionType { Action, Condition, Expression, StringExpression };
|
||||
/**
|
||||
* \brief Get the name of the ExpressionAndCondition to use as an operand
|
||||
* that is defined in the editor.
|
||||
*/
|
||||
const gd::String& GetGetterName() const { return getterName; };
|
||||
|
||||
/**
|
||||
* \brief Set the name of the ExpressionAndCondition to use as an operand
|
||||
* that is defined in the editor.
|
||||
*/
|
||||
EventsFunction& SetGetterName(const gd::String& getterName_) {
|
||||
getterName = getterName_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the type of the expression
|
||||
*/
|
||||
EventsFunction& SetExpressionType(const gd::ValueTypeMetadata& type) {
|
||||
expressionType = type;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the type of the expression
|
||||
*/
|
||||
const gd::ValueTypeMetadata& GetExpressionType() const { return expressionType; }
|
||||
|
||||
enum FunctionType {
|
||||
Action,
|
||||
Condition,
|
||||
Expression,
|
||||
ExpressionAndCondition,
|
||||
ActionWithOperator };
|
||||
|
||||
/**
|
||||
* \brief Set the type of the function
|
||||
@@ -123,12 +158,40 @@ class GD_CORE_API EventsFunction {
|
||||
EventsFunction& SetFunctionType(FunctionType type) {
|
||||
functionType = type;
|
||||
return *this;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the type of the function
|
||||
*/
|
||||
FunctionType GetFunctionType() const { return functionType; };
|
||||
FunctionType GetFunctionType() const { return functionType; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the function is an action.
|
||||
*/
|
||||
bool IsAction() const {
|
||||
return functionType == gd::EventsFunction::Action ||
|
||||
functionType == gd::EventsFunction::ActionWithOperator;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the function is an expression.
|
||||
*
|
||||
* Note that a function can be both an expression and a condition.
|
||||
*/
|
||||
bool IsExpression() const {
|
||||
return functionType == gd::EventsFunction::Expression ||
|
||||
functionType == gd::EventsFunction::ExpressionAndCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the function is a condition.
|
||||
*
|
||||
* Note that a function can be both an expression and a condition.
|
||||
*/
|
||||
bool IsCondition() const {
|
||||
return functionType == gd::EventsFunction::Condition ||
|
||||
functionType == gd::EventsFunction::ExpressionAndCondition;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Returns true if the function is private.
|
||||
@@ -154,7 +217,20 @@ class GD_CORE_API EventsFunction {
|
||||
gd::EventsList& GetEvents() { return events; };
|
||||
|
||||
/**
|
||||
* \brief Return the parameters of the function.
|
||||
* \brief Return the parameters of the function that are used in the events.
|
||||
*
|
||||
* \note During code/extension generation, new parameters are added
|
||||
* to the generated function, like "runtimeScene" and "eventsFunctionContext".
|
||||
* This should be transparent to the user.
|
||||
*/
|
||||
const std::vector<gd::ParameterMetadata>& GetParametersForEvents(
|
||||
const gd::EventsFunctionsContainer& functionsContainer) const;
|
||||
|
||||
/**
|
||||
* \brief Return the parameters of the function that are filled in the editor.
|
||||
*
|
||||
* \note They won't be used for ActionWithOperator, but they need to be kept
|
||||
* to avoid to loose them when the function type is changed.
|
||||
*
|
||||
* \note During code/extension generation, new parameters are added
|
||||
* to the generated function, like "runtimeScene" and "eventsFunctionContext".
|
||||
@@ -202,9 +278,12 @@ class GD_CORE_API EventsFunction {
|
||||
gd::String description;
|
||||
gd::String sentence;
|
||||
gd::String group;
|
||||
gd::String getterName;
|
||||
gd::ValueTypeMetadata expressionType;
|
||||
gd::EventsList events;
|
||||
FunctionType functionType;
|
||||
std::vector<gd::ParameterMetadata> parameters;
|
||||
mutable std::vector<gd::ParameterMetadata> actionWithOperationParameters;
|
||||
gd::ObjectGroupsContainer objectGroups;
|
||||
bool isPrivate = false;
|
||||
};
|
||||
|
@@ -25,7 +25,24 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API EventsFunctionsContainer
|
||||
: private SerializableWithNameList<gd::EventsFunction> {
|
||||
public:
|
||||
public:
|
||||
enum FunctionOwner {
|
||||
Extension,
|
||||
Object,
|
||||
Behavior};
|
||||
|
||||
EventsFunctionsContainer(FunctionOwner source_) : owner(source_) {}
|
||||
|
||||
/**
|
||||
* \brief Get the source of the function container.
|
||||
*
|
||||
* \note For instance, it can be useful to handle specific parameters for
|
||||
* behaviors.
|
||||
*/
|
||||
FunctionOwner GetOwner() const {
|
||||
return owner;
|
||||
}
|
||||
|
||||
/** \name Events Functions management
|
||||
*/
|
||||
///@{
|
||||
@@ -139,6 +156,9 @@ class GD_CORE_API EventsFunctionsContainer
|
||||
void Init(const gd::EventsFunctionsContainer& other) {
|
||||
return SerializableWithNameList<gd::EventsFunction>::Init(other);
|
||||
};
|
||||
|
||||
private:
|
||||
FunctionOwner owner;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -13,10 +13,14 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
EventsFunctionsExtension::EventsFunctionsExtension() {}
|
||||
EventsFunctionsExtension::EventsFunctionsExtension() :
|
||||
gd::EventsFunctionsContainer(
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Extension) {}
|
||||
|
||||
EventsFunctionsExtension::EventsFunctionsExtension(
|
||||
const EventsFunctionsExtension& other) {
|
||||
const EventsFunctionsExtension& other) :
|
||||
gd::EventsFunctionsContainer(
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Extension) {
|
||||
Init(other);
|
||||
}
|
||||
|
||||
|
@@ -20,7 +20,9 @@ class Project;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
// TODO Remove the EventsFunctionsContainer inheritance and make it an attribute.
|
||||
// This will allow to get EventsFunctionsContainer the same way for extensions,
|
||||
// objects and behaviors.
|
||||
/**
|
||||
* \brief Hold a list of Events Functions (gd::EventsFunction) and Events Based
|
||||
* Behaviors.
|
||||
|
@@ -10,7 +10,8 @@
|
||||
|
||||
TEST_CASE("EventsFunctionsContainer", "[common]") {
|
||||
SECTION("Sanity checks") {
|
||||
gd::EventsFunctionsContainer eventsFunctionContainer;
|
||||
gd::EventsFunctionsContainer eventsFunctionContainer(
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Extension);
|
||||
eventsFunctionContainer.InsertNewEventsFunction("Function1", 0);
|
||||
eventsFunctionContainer.InsertNewEventsFunction("Function2", 1);
|
||||
eventsFunctionContainer.InsertNewEventsFunction("Function3", 2);
|
||||
@@ -62,7 +63,8 @@ TEST_CASE("EventsFunctionsContainer", "[common]") {
|
||||
}
|
||||
SECTION("Serialization") {
|
||||
gd::Project project;
|
||||
gd::EventsFunctionsContainer eventsFunctionContainer;
|
||||
gd::EventsFunctionsContainer eventsFunctionContainer(
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Extension);
|
||||
eventsFunctionContainer.InsertNewEventsFunction("Function1", 0);
|
||||
eventsFunctionContainer.InsertNewEventsFunction("Function2", 1);
|
||||
eventsFunctionContainer.InsertNewEventsFunction("Function3", 2);
|
||||
@@ -72,7 +74,8 @@ TEST_CASE("EventsFunctionsContainer", "[common]") {
|
||||
|
||||
eventsFunctionContainer.RemoveEventsFunction("Function2");
|
||||
|
||||
gd::EventsFunctionsContainer eventsFunctionContainer2;
|
||||
gd::EventsFunctionsContainer eventsFunctionContainer2(
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Extension);
|
||||
eventsFunctionContainer2.UnserializeEventsFunctionsFrom(project, element);
|
||||
REQUIRE(eventsFunctionContainer.GetEventsFunctionsCount() == 2);
|
||||
REQUIRE(eventsFunctionContainer.GetEventsFunction(0).GetName() ==
|
||||
|
@@ -70,6 +70,9 @@ const gd::String &GetEventFirstActionType(const gd::BaseEvent &event) {
|
||||
enum TestEvent {
|
||||
FreeFunctionAction,
|
||||
FreeFunctionWithExpression,
|
||||
FreeConditionFromExpressionAndCondition,
|
||||
FreeExpressionFromExpressionAndCondition,
|
||||
FreeActionWithOperator,
|
||||
FreeFunctionWithObjects,
|
||||
FreeFunctionWithObjectExpression,
|
||||
|
||||
@@ -81,6 +84,9 @@ enum TestEvent {
|
||||
IllNamedBehaviorExpression,
|
||||
NoParameterBehaviorExpression,
|
||||
NoParameterIllNamedBehaviorExpression,
|
||||
BehaviorConditionFromExpressionAndCondition,
|
||||
BehaviorExpressionFromExpressionAndCondition,
|
||||
BehaviorActionWithOperator,
|
||||
|
||||
ObjectAction,
|
||||
ObjectPropertyAction,
|
||||
@@ -90,6 +96,9 @@ enum TestEvent {
|
||||
IllNamedObjectExpression,
|
||||
NoParameterObjectExpression,
|
||||
NoParameterIllNamedObjectExpression,
|
||||
ObjectConditionFromExpressionAndCondition,
|
||||
ObjectExpressionFromExpressionAndCondition,
|
||||
ObjectActionWithOperator,
|
||||
};
|
||||
|
||||
const std::vector<const gd::EventsList *> GetEventsLists(gd::Project &project) {
|
||||
@@ -115,7 +124,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
// Add some free functions usages in events
|
||||
{
|
||||
if (eventList.GetEventsCount() != FreeFunctionAction) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsFunction
|
||||
@@ -133,7 +142,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeFunctionWithExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsFunctionExpression
|
||||
@@ -150,8 +159,86 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeConditionFromExpressionAndCondition) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsFunctionExpressionAndCondition
|
||||
// as a condition.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction condition;
|
||||
condition.SetType("MyEventsExtension::MyEventsFunctionExpressionAndCondition");
|
||||
condition.SetParametersCount(5);
|
||||
condition.SetParameter(
|
||||
0,
|
||||
gd::Expression("scene"));
|
||||
condition.SetParameter(
|
||||
1,
|
||||
gd::Expression(">"));
|
||||
condition.SetParameter(
|
||||
2,
|
||||
gd::Expression("2"));
|
||||
condition.SetParameter(
|
||||
3,
|
||||
gd::Expression("111"));
|
||||
condition.SetParameter(
|
||||
4,
|
||||
gd::Expression("222"));
|
||||
event.GetConditions().Insert(condition);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeExpressionFromExpressionAndCondition) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsFunctionExpressionAndCondition
|
||||
// as an expression.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomething");
|
||||
action.SetParametersCount(1);
|
||||
action.SetParameter(
|
||||
0,
|
||||
gd::Expression(
|
||||
"2 + MyEventsExtension::MyEventsFunctionExpressionAndCondition(111, 222)"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeActionWithOperator) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsFunctionActionWithOperator
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyEventsExtension::MyEventsFunctionActionWithOperator");
|
||||
action.SetParametersCount(5);
|
||||
action.SetParameter(
|
||||
0,
|
||||
gd::Expression("scene"));
|
||||
action.SetParameter(
|
||||
1,
|
||||
gd::Expression("+"));
|
||||
action.SetParameter(
|
||||
2,
|
||||
gd::Expression("2"));
|
||||
action.SetParameter(
|
||||
3,
|
||||
gd::Expression("111"));
|
||||
action.SetParameter(
|
||||
4,
|
||||
gd::Expression("222"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeFunctionWithObjects) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to objects
|
||||
{
|
||||
@@ -166,7 +253,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != FreeFunctionWithObjectExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to objects in an expression
|
||||
{
|
||||
@@ -186,7 +273,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
// Add some events based behavior usages in events
|
||||
{
|
||||
if (eventList.GetEventsCount() != BehaviorAction) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event in the layout referring to
|
||||
// MyEventsExtension::MyEventsBasedBehavior::MyBehaviorEventsFunction
|
||||
@@ -206,7 +293,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != BehaviorPropertyAction) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event in the layout using "MyProperty" action
|
||||
{
|
||||
@@ -220,7 +307,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != BehaviorPropertyCondition) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event in the layout using "MyProperty" condition
|
||||
{
|
||||
@@ -234,7 +321,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != BehaviorPropertyExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event in the layout using "MyProperty" expression
|
||||
{
|
||||
@@ -252,7 +339,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != BehaviorExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsBasedBehavior::MyBehaviorEventsFunctionExpression
|
||||
@@ -271,7 +358,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != IllNamedBehaviorExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event **wrongly** referring to
|
||||
// MyEventsExtension::MyEventsBasedBehavior::MyBehaviorEventsFunctionExpression
|
||||
@@ -291,7 +378,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != NoParameterBehaviorExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsBasedBehavior::MyBehaviorEventsFunctionExpression
|
||||
@@ -310,7 +397,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != NoParameterIllNamedBehaviorExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event **wrongly** referring to
|
||||
// MyEventsExtension::MyEventsBasedBehavior::MyBehaviorEventsFunctionExpression
|
||||
@@ -327,12 +414,99 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
event.GetActions().Insert(instruction);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != BehaviorConditionFromExpressionAndCondition) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsBasedBehavior::MyBehaviorEventsFunctionExpressionAndCondition
|
||||
// as a condition.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction condition;
|
||||
condition.SetType("MyEventsExtension::MyEventsBasedBehavior::"
|
||||
"MyBehaviorEventsFunctionExpressionAndCondition");
|
||||
condition.SetParametersCount(6);
|
||||
condition.SetParameter(
|
||||
0,
|
||||
gd::Expression("ObjectWithMyBehavior"));
|
||||
condition.SetParameter(
|
||||
1,
|
||||
gd::Expression("MyBehavior"));
|
||||
condition.SetParameter(
|
||||
2,
|
||||
gd::Expression(">"));
|
||||
condition.SetParameter(
|
||||
3,
|
||||
gd::Expression("5"));
|
||||
condition.SetParameter(
|
||||
4,
|
||||
gd::Expression("111"));
|
||||
condition.SetParameter(
|
||||
5,
|
||||
gd::Expression("222"));
|
||||
event.GetConditions().Insert(condition);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != BehaviorExpressionFromExpressionAndCondition) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsBasedBehavior::MyBehaviorEventsFunctionExpressionAndCondition
|
||||
// as an expression.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomething");
|
||||
action.SetParametersCount(1);
|
||||
action.SetParameter(
|
||||
0,
|
||||
gd::Expression("5 + "
|
||||
"ObjectWithMyBehavior.MyBehavior::"
|
||||
"MyBehaviorEventsFunctionExpressionAndCondition(111, 222)"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != BehaviorActionWithOperator) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsBasedBehavior::MyBehaviorEventsFunctionActionWithOperator
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyEventsExtension::MyEventsBasedBehavior::"
|
||||
"MyBehaviorEventsFunctionActionWithOperator");
|
||||
action.SetParametersCount(6);
|
||||
action.SetParameter(
|
||||
0,
|
||||
gd::Expression("ObjectWithMyBehavior"));
|
||||
action.SetParameter(
|
||||
1,
|
||||
gd::Expression("MyBehavior"));
|
||||
action.SetParameter(
|
||||
2,
|
||||
gd::Expression("+"));
|
||||
action.SetParameter(
|
||||
3,
|
||||
gd::Expression("5"));
|
||||
action.SetParameter(
|
||||
4,
|
||||
gd::Expression("111"));
|
||||
action.SetParameter(
|
||||
5,
|
||||
gd::Expression("222"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
// Add some events based object usages in events
|
||||
{
|
||||
if (eventList.GetEventsCount() != ObjectAction) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event in the layout referring to
|
||||
// MyEventsExtension::MyEventsBasedObject::MyObjectEventsFunction
|
||||
@@ -351,7 +525,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != ObjectPropertyAction) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event in the layout using "MyProperty" action
|
||||
{
|
||||
@@ -365,7 +539,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != ObjectPropertyCondition) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event in the layout using "MyProperty" condition
|
||||
{
|
||||
@@ -379,7 +553,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != ObjectPropertyExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event in the layout using "MyProperty" expression
|
||||
{
|
||||
@@ -397,7 +571,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != ObjectExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsBasedObject::MyObjectEventsFunctionExpression
|
||||
@@ -415,7 +589,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != IllNamedObjectExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event **wrongly** referring to
|
||||
// MyEventsExtension::MyEventsBasedObject::MyObjectEventsFunctionExpression
|
||||
@@ -434,7 +608,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != NoParameterObjectExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsBasedObject::MyObjectEventsFunctionExpression
|
||||
@@ -453,7 +627,7 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != NoParameterIllNamedObjectExpression) {
|
||||
throw std::logic_error("Invalid events setup");
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event **wrongly** referring to
|
||||
// MyEventsExtension::MyEventsBasedObject::MyObjectEventsFunctionExpression
|
||||
@@ -470,6 +644,87 @@ const void SetupEvents(gd::EventsList &eventList) {
|
||||
event.GetActions().Insert(instruction);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != ObjectConditionFromExpressionAndCondition) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsBasedObject::MyObjectEventsFunctionExpressionAndCondition
|
||||
// as a condition.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction condition;
|
||||
condition.SetType("MyEventsExtension::MyEventsBasedObject::"
|
||||
"MyObjectEventsFunctionExpressionAndCondition");
|
||||
condition.SetParametersCount(5);
|
||||
condition.SetParameter(
|
||||
0,
|
||||
gd::Expression("MyCustomObject"));
|
||||
condition.SetParameter(
|
||||
1,
|
||||
gd::Expression(">"));
|
||||
condition.SetParameter(
|
||||
2,
|
||||
gd::Expression("5"));
|
||||
condition.SetParameter(
|
||||
3,
|
||||
gd::Expression("111"));
|
||||
condition.SetParameter(
|
||||
4,
|
||||
gd::Expression("222"));
|
||||
event.GetConditions().Insert(condition);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != ObjectExpressionFromExpressionAndCondition) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsBasedObject::MyObjectEventsFunctionExpressionAndCondition
|
||||
// as an expression.
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyExtension::DoSomething");
|
||||
action.SetParametersCount(1);
|
||||
action.SetParameter(
|
||||
0,
|
||||
gd::Expression("5 + "
|
||||
"MyCustomObject."
|
||||
"MyObjectEventsFunctionExpressionAndCondition(111, 222)"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
|
||||
if (eventList.GetEventsCount() != ObjectActionWithOperator) {
|
||||
throw std::logic_error("Invalid events setup: " + std::to_string(eventList.GetEventsCount()));
|
||||
}
|
||||
// Create an event referring to
|
||||
// MyEventsExtension::MyEventsBasedObject::MyObjectEventsFunctionActionWithOperator
|
||||
{
|
||||
gd::StandardEvent event;
|
||||
gd::Instruction action;
|
||||
action.SetType("MyEventsExtension::MyEventsBasedObject::"
|
||||
"MyObjectEventsFunctionActionWithOperator");
|
||||
action.SetParametersCount(5);
|
||||
action.SetParameter(
|
||||
0,
|
||||
gd::Expression("MyCustomObject"));
|
||||
action.SetParameter(
|
||||
1,
|
||||
gd::Expression("+"));
|
||||
action.SetParameter(
|
||||
2,
|
||||
gd::Expression("5"));
|
||||
action.SetParameter(
|
||||
3,
|
||||
gd::Expression("111"));
|
||||
action.SetParameter(
|
||||
4,
|
||||
gd::Expression("222"));
|
||||
event.GetActions().Insert(action);
|
||||
eventList.InsertEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,6 +782,31 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
.SetType("behavior")
|
||||
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
|
||||
|
||||
auto &behaviorExpressionAndCondition =
|
||||
behaviorEventsFunctions
|
||||
.InsertNewEventsFunction("MyBehaviorEventsFunctionExpressionAndCondition", 2)
|
||||
.SetFunctionType(gd::EventsFunction::ExpressionAndCondition);
|
||||
behaviorExpressionAndCondition.GetParameters().push_back(
|
||||
gd::ParameterMetadata().SetName("Object").SetType("object"));
|
||||
behaviorExpressionAndCondition.GetParameters().push_back(
|
||||
gd::ParameterMetadata()
|
||||
.SetName("Behavior")
|
||||
.SetType("behavior")
|
||||
.SetExtraInfo("MyExtension::MyEventsBasedBehavior"));
|
||||
behaviorExpressionAndCondition.GetParameters().push_back(
|
||||
gd::ParameterMetadata()
|
||||
.SetName("Value1")
|
||||
.SetType("expression"));
|
||||
behaviorExpressionAndCondition.GetParameters().push_back(
|
||||
gd::ParameterMetadata()
|
||||
.SetName("Value2")
|
||||
.SetType("expression"));
|
||||
|
||||
behaviorEventsFunctions
|
||||
.InsertNewEventsFunction("MyBehaviorEventsFunctionActionWithOperator", 2)
|
||||
.SetFunctionType(gd::EventsFunction::ActionWithOperator)
|
||||
.SetGetterName("MyBehaviorEventsFunctionExpressionAndCondition");
|
||||
|
||||
// Add property
|
||||
eventsBasedBehavior.GetPropertyDescriptors()
|
||||
.InsertNew("MyProperty", 0)
|
||||
@@ -570,6 +850,26 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
.SetType("object")
|
||||
.SetExtraInfo("MyEventsExtension::MyEventsBasedObject"));
|
||||
|
||||
auto &objectExpressionAndCondition =
|
||||
objectEventsFunctions
|
||||
.InsertNewEventsFunction("MyObjectEventsFunctionExpressionAndCondition", 2)
|
||||
.SetFunctionType(gd::EventsFunction::ExpressionAndCondition);
|
||||
objectExpressionAndCondition.GetParameters().push_back(
|
||||
gd::ParameterMetadata().SetName("Object").SetType("object"));
|
||||
objectExpressionAndCondition.GetParameters().push_back(
|
||||
gd::ParameterMetadata()
|
||||
.SetName("Value1")
|
||||
.SetType("expression"));
|
||||
objectExpressionAndCondition.GetParameters().push_back(
|
||||
gd::ParameterMetadata()
|
||||
.SetName("Value2")
|
||||
.SetType("expression"));
|
||||
|
||||
objectEventsFunctions
|
||||
.InsertNewEventsFunction("MyObjectEventsFunctionActionWithOperator", 2)
|
||||
.SetFunctionType(gd::EventsFunction::ActionWithOperator)
|
||||
.SetGetterName("MyObjectEventsFunctionExpressionAndCondition");
|
||||
|
||||
// Add a property
|
||||
eventsBasedObject.GetPropertyDescriptors()
|
||||
.InsertNew("MyProperty", 0)
|
||||
@@ -622,6 +922,7 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
.SetName("Behavior")
|
||||
.SetType("behavior")
|
||||
.SetExtraInfo("MyEventsExtension::MyEventsBasedBehavior"));
|
||||
|
||||
auto &expression =
|
||||
eventsExtension.InsertNewEventsFunction("MyEventsFunctionExpression", 1)
|
||||
.SetFunctionType(gd::EventsFunction::Expression);
|
||||
@@ -629,6 +930,21 @@ SetupProjectWithEventsFunctionExtension(gd::Project &project) {
|
||||
.SetName("currentScene")
|
||||
.SetType("")
|
||||
.SetCodeOnly(true));
|
||||
|
||||
auto &freeExpressionAndCondition = eventsExtension.InsertNewEventsFunction("MyEventsFunctionExpressionAndCondition", 2)
|
||||
.SetFunctionType(gd::EventsFunction::ExpressionAndCondition);
|
||||
freeExpressionAndCondition.GetParameters().push_back(
|
||||
gd::ParameterMetadata()
|
||||
.SetName("Value1")
|
||||
.SetType("expression"));
|
||||
freeExpressionAndCondition.GetParameters().push_back(
|
||||
gd::ParameterMetadata()
|
||||
.SetName("Value2")
|
||||
.SetType("expression"));
|
||||
|
||||
eventsExtension.InsertNewEventsFunction("MyEventsFunctionActionWithOperator", 2)
|
||||
.SetFunctionType(gd::EventsFunction::ActionWithOperator)
|
||||
.SetGetterName("MyEventsFunctionExpressionAndCondition");
|
||||
}
|
||||
|
||||
// Add some usages in events
|
||||
@@ -1048,6 +1364,21 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
eventsList->GetEvent(FreeFunctionWithExpression)) ==
|
||||
"1 + MyRenamedExtension::MyEventsFunctionExpression(123, 456)");
|
||||
|
||||
// Check that events function calls from an ExpressionAndCondition have
|
||||
// been renamed.
|
||||
REQUIRE(GetEventFirstConditionType(
|
||||
eventsList->GetEvent(FreeConditionFromExpressionAndCondition)) ==
|
||||
"MyRenamedExtension::MyEventsFunctionExpressionAndCondition");
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(FreeExpressionFromExpressionAndCondition)) ==
|
||||
"2 + MyRenamedExtension::MyEventsFunctionExpressionAndCondition(111, 222)");
|
||||
|
||||
// Check that events function calls from an ActionWithOperator has
|
||||
// been renamed.
|
||||
REQUIRE(GetEventFirstActionType(
|
||||
eventsList->GetEvent(FreeActionWithOperator)) ==
|
||||
"MyRenamedExtension::MyEventsFunctionActionWithOperator");
|
||||
|
||||
// Check that the type of the behavior was changed in the behaviors of
|
||||
// objects. Name is *not* changed.
|
||||
REQUIRE(project.GetLayout("Scene")
|
||||
@@ -1084,7 +1415,17 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
REQUIRE(GetEventFirstActionType(eventsList->GetEvent(BehaviorAction)) ==
|
||||
"MyRenamedExtension::MyEventsBasedBehavior::"
|
||||
"MyBehaviorEventsFunction");
|
||||
|
||||
REQUIRE(
|
||||
GetEventFirstConditionType(
|
||||
eventsList->GetEvent(BehaviorConditionFromExpressionAndCondition)) ==
|
||||
"MyRenamedExtension::MyEventsBasedBehavior::"
|
||||
"MyBehaviorEventsFunctionExpressionAndCondition");
|
||||
REQUIRE(
|
||||
GetEventFirstActionType(
|
||||
eventsList->GetEvent(BehaviorActionWithOperator)) ==
|
||||
"MyRenamedExtension::MyEventsBasedBehavior::"
|
||||
"MyBehaviorEventsFunctionActionWithOperator");
|
||||
|
||||
// Check if events-based behaviors properties have been renamed in
|
||||
// instructions
|
||||
REQUIRE(GetEventFirstActionType(
|
||||
@@ -1096,16 +1437,19 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
// expressions
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(BehaviorExpression)) ==
|
||||
"1 + "
|
||||
"ObjectWithMyBehavior.MyBehavior::"
|
||||
"1 + ObjectWithMyBehavior.MyBehavior::"
|
||||
"MyBehaviorEventsFunctionExpression(123, 456, 789)");
|
||||
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(NoParameterBehaviorExpression)) ==
|
||||
"3 + "
|
||||
"ObjectWithMyBehavior.MyBehavior::"
|
||||
"3 + ObjectWithMyBehavior.MyBehavior::"
|
||||
"MyBehaviorEventsFunctionExpression");
|
||||
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(BehaviorExpressionFromExpressionAndCondition)) ==
|
||||
"5 + ObjectWithMyBehavior.MyBehavior::"
|
||||
"MyBehaviorEventsFunctionExpressionAndCondition(111, 222)");
|
||||
|
||||
// Check that the type of the object was changed in the custom
|
||||
// objects. Name is *not* changed.
|
||||
REQUIRE(
|
||||
@@ -1119,6 +1463,16 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
REQUIRE(
|
||||
GetEventFirstActionType(eventsList->GetEvent(ObjectAction)) ==
|
||||
"MyRenamedExtension::MyEventsBasedObject::MyObjectEventsFunction");
|
||||
REQUIRE(
|
||||
GetEventFirstConditionType(
|
||||
eventsList->GetEvent(ObjectConditionFromExpressionAndCondition)) ==
|
||||
"MyRenamedExtension::MyEventsBasedObject::"
|
||||
"MyObjectEventsFunctionExpressionAndCondition");
|
||||
REQUIRE(
|
||||
GetEventFirstActionType(
|
||||
eventsList->GetEvent(ObjectActionWithOperator)) ==
|
||||
"MyRenamedExtension::MyEventsBasedObject::"
|
||||
"MyObjectEventsFunctionActionWithOperator");
|
||||
|
||||
// Check if events-based object properties have been renamed in
|
||||
// instructions
|
||||
@@ -1130,14 +1484,17 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
// expressions
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(ObjectExpression)) ==
|
||||
"1 + "
|
||||
"MyCustomObject."
|
||||
"1 + MyCustomObject."
|
||||
"MyObjectEventsFunctionExpression(123, 456, 789)");
|
||||
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(NoParameterObjectExpression)) ==
|
||||
"3 + "
|
||||
"MyCustomObject.MyObjectEventsFunctionExpression");
|
||||
"3 + MyCustomObject.MyObjectEventsFunctionExpression");
|
||||
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(ObjectExpressionFromExpressionAndCondition)) ==
|
||||
"5 + MyCustomObject."
|
||||
"MyObjectEventsFunctionExpressionAndCondition(111, 222)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1239,6 +1596,35 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Free) events expression and condition renamed") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
gd::WholeProjectRefactorer::RenameEventsFunction(
|
||||
project,
|
||||
eventsExtension,
|
||||
"MyEventsFunctionExpressionAndCondition",
|
||||
"MyRenamedFunctionExpressionAndCondition");
|
||||
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check that events function calls in expressions have been renamed
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(FreeExpressionFromExpressionAndCondition)) ==
|
||||
"2 + MyEventsExtension::MyRenamedFunctionExpressionAndCondition(111, 222)");
|
||||
|
||||
// Check that events function calls in instructions have been renamed
|
||||
REQUIRE(GetEventFirstConditionType(
|
||||
eventsList->GetEvent(FreeConditionFromExpressionAndCondition)) ==
|
||||
"MyEventsExtension::MyRenamedFunctionExpressionAndCondition");
|
||||
|
||||
// Check that the action still refer to the right ExpressionAndCondition.
|
||||
REQUIRE(eventsExtension.GetEventsFunction("MyEventsFunctionActionWithOperator")
|
||||
.GetGetterName() == "MyRenamedFunctionExpressionAndCondition");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Free) events action parameter moved") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -1279,6 +1665,35 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Free) events expression and condition parameter moved") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
// The index 0 is reserved for the RuntimeScene.
|
||||
gd::WholeProjectRefactorer::MoveEventsFunctionParameter(
|
||||
project, eventsExtension, "MyEventsFunctionExpressionAndCondition", 1, 2);
|
||||
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check that events function calls in expressions have been updated
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(FreeExpressionFromExpressionAndCondition)) ==
|
||||
"2 + MyEventsExtension::MyEventsFunctionExpressionAndCondition(222, 111)");
|
||||
|
||||
// Check that events function calls in instructions have been updated
|
||||
auto &condition = static_cast<const gd::StandardEvent &>(
|
||||
eventsList->GetEvent(FreeConditionFromExpressionAndCondition))
|
||||
.GetConditions()
|
||||
.Get(0);
|
||||
REQUIRE(condition.GetParameter(0).GetPlainString() == "scene");
|
||||
REQUIRE(condition.GetParameter(1).GetPlainString() == ">");
|
||||
REQUIRE(condition.GetParameter(2).GetPlainString() == "2");
|
||||
REQUIRE(condition.GetParameter(3).GetPlainString() == "222");
|
||||
REQUIRE(condition.GetParameter(4).GetPlainString() == "111");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Events based behavior renamed (instructions update)") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -1316,6 +1731,14 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
REQUIRE(GetEventFirstActionType(eventsList->GetEvent(BehaviorAction)) ==
|
||||
"MyEventsExtension::MyRenamedEventsBasedBehavior::"
|
||||
"MyBehaviorEventsFunction");
|
||||
REQUIRE(GetEventFirstConditionType(
|
||||
eventsList->GetEvent(BehaviorConditionFromExpressionAndCondition)) ==
|
||||
"MyEventsExtension::MyRenamedEventsBasedBehavior::"
|
||||
"MyBehaviorEventsFunctionExpressionAndCondition");
|
||||
REQUIRE(GetEventFirstActionType(
|
||||
eventsList->GetEvent(BehaviorActionWithOperator)) ==
|
||||
"MyEventsExtension::MyRenamedEventsBasedBehavior::"
|
||||
"MyBehaviorEventsFunctionActionWithOperator");
|
||||
|
||||
// Check if events-based behaviors properties have been renamed in
|
||||
// instructions
|
||||
@@ -1328,9 +1751,12 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
// expressions
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(BehaviorExpression)) ==
|
||||
"1 + "
|
||||
"ObjectWithMyBehavior.MyBehavior::"
|
||||
"1 + ObjectWithMyBehavior.MyBehavior::"
|
||||
"MyBehaviorEventsFunctionExpression(123, 456, 789)");
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(BehaviorExpressionFromExpressionAndCondition)) ==
|
||||
"5 + ObjectWithMyBehavior.MyBehavior::"
|
||||
"MyBehaviorEventsFunctionExpressionAndCondition(111, 222)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1407,6 +1833,14 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
REQUIRE(GetEventFirstActionType(eventsList->GetEvent(ObjectAction)) ==
|
||||
"MyEventsExtension::MyRenamedEventsBasedObject::"
|
||||
"MyObjectEventsFunction");
|
||||
REQUIRE(GetEventFirstConditionType(
|
||||
eventsList->GetEvent(ObjectConditionFromExpressionAndCondition)) ==
|
||||
"MyEventsExtension::MyRenamedEventsBasedObject::"
|
||||
"MyObjectEventsFunctionExpressionAndCondition");
|
||||
REQUIRE(GetEventFirstActionType(
|
||||
eventsList->GetEvent(ObjectActionWithOperator)) ==
|
||||
"MyEventsExtension::MyRenamedEventsBasedObject::"
|
||||
"MyObjectEventsFunctionActionWithOperator");
|
||||
|
||||
// Check if events-based object properties have been renamed in
|
||||
// instructions
|
||||
@@ -1419,9 +1853,12 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
// expressions
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(ObjectExpression)) ==
|
||||
"1 + "
|
||||
"MyCustomObject."
|
||||
"1 + MyCustomObject."
|
||||
"MyObjectEventsFunctionExpression(123, 456, 789)");
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(ObjectExpressionFromExpressionAndCondition)) ==
|
||||
"5 + MyCustomObject."
|
||||
"MyObjectEventsFunctionExpressionAndCondition(111, 222)");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1623,6 +2060,80 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Events based behavior) events expression and condition renamed") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().Get("MyEventsBasedBehavior");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameBehaviorEventsFunction(
|
||||
project,
|
||||
eventsExtension,
|
||||
eventsBasedBehavior,
|
||||
"MyBehaviorEventsFunctionExpressionAndCondition",
|
||||
"MyRenamedBehaviorEventsFunctionExpressionAndCondition");
|
||||
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check events-based behavior methods have been renamed in
|
||||
// expressions
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(BehaviorExpressionFromExpressionAndCondition)) ==
|
||||
"5 + ObjectWithMyBehavior.MyBehavior::"
|
||||
"MyRenamedBehaviorEventsFunctionExpressionAndCondition(111, 222)");
|
||||
|
||||
// Check if events-based behavior methods have been renamed in
|
||||
// instructions
|
||||
REQUIRE(GetEventFirstConditionType(
|
||||
eventsList->GetEvent(BehaviorConditionFromExpressionAndCondition)) ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::"
|
||||
"MyRenamedBehaviorEventsFunctionExpressionAndCondition");
|
||||
|
||||
// Check that the action still refer to the right ExpressionAndCondition.
|
||||
REQUIRE(eventsBasedBehavior.GetEventsFunctions()
|
||||
.GetEventsFunction("MyBehaviorEventsFunctionActionWithOperator")
|
||||
.GetGetterName() == "MyRenamedBehaviorEventsFunctionExpressionAndCondition");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Events based object) events expression and condition renamed") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedObject =
|
||||
eventsExtension.GetEventsBasedObjects().Get("MyEventsBasedObject");
|
||||
|
||||
gd::WholeProjectRefactorer::RenameObjectEventsFunction(
|
||||
project,
|
||||
eventsExtension,
|
||||
eventsBasedObject,
|
||||
"MyObjectEventsFunctionExpressionAndCondition",
|
||||
"MyRenamedObjectEventsFunctionExpressionAndCondition");
|
||||
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check events-based behavior methods have been renamed in
|
||||
// expressions
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(ObjectExpressionFromExpressionAndCondition)) ==
|
||||
"5 + MyCustomObject."
|
||||
"MyRenamedObjectEventsFunctionExpressionAndCondition(111, 222)");
|
||||
|
||||
// Check if events-based behavior methods have been renamed in
|
||||
// instructions
|
||||
REQUIRE(GetEventFirstConditionType(
|
||||
eventsList->GetEvent(ObjectConditionFromExpressionAndCondition)) ==
|
||||
"MyEventsExtension::MyEventsBasedObject::"
|
||||
"MyRenamedObjectEventsFunctionExpressionAndCondition");
|
||||
|
||||
// Check that the action still refer to the right ExpressionAndCondition.
|
||||
REQUIRE(eventsBasedObject.GetEventsFunctions()
|
||||
.GetEventsFunction("MyObjectEventsFunctionActionWithOperator")
|
||||
.GetGetterName() == "MyRenamedObjectEventsFunctionExpressionAndCondition");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Events based behavior) events action parameter moved") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
@@ -1739,6 +2250,83 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Events based behavior) events expression and condition parameter moved") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().Get("MyEventsBasedBehavior");
|
||||
|
||||
// The first 2 parameters are reserved for the object and behavior.
|
||||
gd::WholeProjectRefactorer::MoveBehaviorEventsFunctionParameter(
|
||||
project,
|
||||
eventsExtension,
|
||||
eventsBasedBehavior,
|
||||
"MyBehaviorEventsFunctionExpressionAndCondition",
|
||||
2,
|
||||
3);
|
||||
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check parameters of events-based behavior methods have been moved in
|
||||
// expressions
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(BehaviorExpressionFromExpressionAndCondition)) ==
|
||||
"5 + ObjectWithMyBehavior.MyBehavior::"
|
||||
"MyBehaviorEventsFunctionExpressionAndCondition(222, 111)");
|
||||
// Check if parameters of events-based behavior methods have been moved in
|
||||
// instructions
|
||||
auto &action = static_cast<const gd::StandardEvent &>(
|
||||
eventsList->GetEvent(BehaviorConditionFromExpressionAndCondition))
|
||||
.GetConditions()
|
||||
.Get(0);
|
||||
REQUIRE(action.GetParameter(0).GetPlainString() == "ObjectWithMyBehavior");
|
||||
REQUIRE(action.GetParameter(1).GetPlainString() == "MyBehavior");
|
||||
REQUIRE(action.GetParameter(2).GetPlainString() == ">");
|
||||
REQUIRE(action.GetParameter(3).GetPlainString() == "5");
|
||||
REQUIRE(action.GetParameter(4).GetPlainString() == "222");
|
||||
REQUIRE(action.GetParameter(5).GetPlainString() == "111");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("(Events based object) events expression and condition parameter moved") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
auto &eventsBasedObject =
|
||||
eventsExtension.GetEventsBasedObjects().Get("MyEventsBasedObject");
|
||||
|
||||
// The first 2 parameters are reserved for the object and behavior.
|
||||
gd::WholeProjectRefactorer::MoveObjectEventsFunctionParameter(
|
||||
project,
|
||||
eventsExtension,
|
||||
eventsBasedObject,
|
||||
"MyObjectEventsFunctionExpressionAndCondition",
|
||||
1,
|
||||
2);
|
||||
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check parameters of events-based behavior methods have been moved in
|
||||
// expressions
|
||||
REQUIRE(GetEventFirstActionFirstParameterString(
|
||||
eventsList->GetEvent(ObjectExpressionFromExpressionAndCondition)) ==
|
||||
"5 + MyCustomObject."
|
||||
"MyObjectEventsFunctionExpressionAndCondition(222, 111)");
|
||||
// Check if parameters of events-based behavior methods have been moved in
|
||||
// instructions
|
||||
auto &action = static_cast<const gd::StandardEvent &>(
|
||||
eventsList->GetEvent(ObjectConditionFromExpressionAndCondition))
|
||||
.GetConditions()
|
||||
.Get(0);
|
||||
REQUIRE(action.GetParameter(0).GetPlainString() == "MyCustomObject");
|
||||
REQUIRE(action.GetParameter(1).GetPlainString() == ">");
|
||||
REQUIRE(action.GetParameter(2).GetPlainString() == "5");
|
||||
REQUIRE(action.GetParameter(3).GetPlainString() == "222");
|
||||
REQUIRE(action.GetParameter(4).GetPlainString() == "111");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION(
|
||||
"(Events based behavior) property renamed (not a required behavior)") {
|
||||
gd::Project project;
|
||||
|
@@ -116,6 +116,7 @@ gd::String EventsCodeGenerator::GenerateLayoutCode(
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsContainer& functionsContainer,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
std::set<gd::String>& includeFiles,
|
||||
@@ -123,7 +124,7 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
project, eventsFunction, globalObjectsAndGroups, objectsAndGroups);
|
||||
project, functionsContainer, eventsFunction, globalObjectsAndGroups, objectsAndGroups);
|
||||
|
||||
EventsCodeGenerator codeGenerator(globalObjectsAndGroups, objectsAndGroups);
|
||||
codeGenerator.SetCodeNamespace(codeNamespace);
|
||||
@@ -133,9 +134,9 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionCode(
|
||||
codeGenerator,
|
||||
codeGenerator.GetCodeNamespaceAccessor() + "func",
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParameters(), 0, true),
|
||||
eventsFunction.GetParametersForEvents(functionsContainer), 0, true),
|
||||
codeGenerator.GenerateFreeEventsFunctionContext(
|
||||
eventsFunction.GetParameters(), "runtimeScene.getOnceTriggers()"),
|
||||
eventsFunction.GetParametersForEvents(functionsContainer), "runtimeScene.getOnceTriggers()"),
|
||||
eventsFunction.GetEvents(),
|
||||
"",
|
||||
codeGenerator.GenerateEventsFunctionReturn(eventsFunction));
|
||||
@@ -185,7 +186,8 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
"var Behavior = this.name;\n" +
|
||||
codeGenerator.GenerateBehaviorEventsFunctionContext(
|
||||
eventsBasedBehavior,
|
||||
eventsFunction.GetParameters(),
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsBasedBehavior.GetEventsFunctions()),
|
||||
onceTriggersVariable,
|
||||
// Pass the names of the parameters considered as the current
|
||||
// object and behavior parameters:
|
||||
@@ -196,7 +198,8 @@ gd::String EventsCodeGenerator::GenerateBehaviorEventsFunctionCode(
|
||||
codeGenerator,
|
||||
fullyQualifiedFunctionName,
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
eventsFunction.GetParameters(), 2, false),
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsBasedBehavior.GetEventsFunctions()), 2, false),
|
||||
fullPreludeCode,
|
||||
eventsFunction.GetEvents(),
|
||||
"",
|
||||
@@ -258,7 +261,8 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
|
||||
fullPreludeCode += codeGenerator.GenerateObjectEventsFunctionContext(
|
||||
eventsBasedObject,
|
||||
eventsFunction.GetParameters(),
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsBasedObject.GetEventsFunctions()),
|
||||
onceTriggersVariable,
|
||||
// Pass the names of the parameters considered as the current
|
||||
// object and behavior parameters:
|
||||
@@ -269,7 +273,8 @@ gd::String EventsCodeGenerator::GenerateObjectEventsFunctionCode(
|
||||
fullyQualifiedFunctionName,
|
||||
codeGenerator.GenerateEventsFunctionParameterDeclarationsList(
|
||||
// TODO EBO use constants for firstParameterIndex
|
||||
eventsFunction.GetParameters(), 1, false),
|
||||
eventsFunction.GetParametersForEvents(
|
||||
eventsBasedObject.GetEventsFunctions()), 1, false),
|
||||
fullPreludeCode,
|
||||
eventsFunction.GetEvents(),
|
||||
endingCode,
|
||||
@@ -557,16 +562,20 @@ gd::String EventsCodeGenerator::GenerateEventsFunctionContext(
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateEventsFunctionReturn(
|
||||
const gd::EventsFunction& eventsFunction) {
|
||||
// We don't use IsCondition because ExpressionAndCondition event functions
|
||||
// don't need a boolean function. They use the expression function with a
|
||||
// relational operator.
|
||||
if (eventsFunction.GetFunctionType() == gd::EventsFunction::Condition) {
|
||||
return "return !!eventsFunctionContext.returnValue;";
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::Expression) {
|
||||
return "return Number(eventsFunctionContext.returnValue) || 0;";
|
||||
} else if (eventsFunction.GetFunctionType() ==
|
||||
gd::EventsFunction::StringExpression) {
|
||||
return "return \"\" + eventsFunctionContext.returnValue;";
|
||||
} else if (eventsFunction.IsExpression()) {
|
||||
if (eventsFunction.GetExpressionType().IsNumber()) {
|
||||
return "return Number(eventsFunctionContext.returnValue) || 0;";
|
||||
} else {
|
||||
// Default on string because it's more likely that future expression
|
||||
// types are strings.
|
||||
return "return \"\" + eventsFunctionContext.returnValue;";
|
||||
}
|
||||
}
|
||||
|
||||
return "return;";
|
||||
}
|
||||
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "GDCore/Events/InstructionsList.h"
|
||||
namespace gd {
|
||||
class ObjectsContainer;
|
||||
class EventsFunctionsContainer;
|
||||
class EventsFunction;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
@@ -55,6 +56,7 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
* Generate JavaScript for executing events of an events based function.
|
||||
*
|
||||
* \param project Project used.
|
||||
* \param functionsContainer The container of the compiled event function.
|
||||
* \param eventsFunction The events function to be compiled.
|
||||
* \param codeNamespace Where to store the context used by the function.
|
||||
* \param includeFiles Will be filled with the necessary include files.
|
||||
@@ -65,6 +67,7 @@ class EventsCodeGenerator : public gd::EventsCodeGenerator {
|
||||
*/
|
||||
static gd::String GenerateEventsFunctionCode(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsContainer& functionsContainer,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
std::set<gd::String>& includeFiles,
|
||||
|
@@ -11,6 +11,7 @@
|
||||
namespace gdjs {
|
||||
gd::String
|
||||
EventsFunctionsExtensionCodeGenerator::GenerateFreeEventsFunctionCompleteCode(
|
||||
const gd::EventsFunctionsExtension& extension,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
std::set<gd::String>& includeFiles,
|
||||
@@ -27,6 +28,7 @@ if (typeof CODE_NAMESPACE !== "undefined") {
|
||||
|
||||
gd::String eventsFunctionCode =
|
||||
EventsCodeGenerator::GenerateEventsFunctionCode(project,
|
||||
extension,
|
||||
eventsFunction,
|
||||
codeNamespace,
|
||||
includeFiles,
|
||||
|
@@ -29,6 +29,7 @@ class EventsFunctionsExtensionCodeGenerator {
|
||||
* \brief Generate the complete code for the specified events function.
|
||||
*/
|
||||
gd::String GenerateFreeEventsFunctionCompleteCode(
|
||||
const gd::EventsFunctionsExtension& extension,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
const gd::String& codeNamespace,
|
||||
std::set<gd::String>& includeFiles,
|
||||
|
@@ -1200,8 +1200,8 @@ interface InstructionMetadata {
|
||||
[Ref] InstructionMetadata SetParameterLongDescription([Const] DOMString longDescription);
|
||||
[Ref] InstructionMetadata SetParameterExtraInfo([Const] DOMString extraInfo);
|
||||
|
||||
[Ref] InstructionMetadata UseStandardOperatorParameters([Const] DOMString type);
|
||||
[Ref] InstructionMetadata UseStandardRelationalOperatorParameters([Const] DOMString type);
|
||||
[Ref] InstructionMetadata UseStandardOperatorParameters([Const] DOMString type, [Const] optional DOMString typeExtraInfo = "");
|
||||
[Ref] InstructionMetadata UseStandardRelationalOperatorParameters([Const] DOMString type, [Const] optional DOMString typeExtraInfo = "");
|
||||
|
||||
[Ref] InstructionMetadata SetRequiresBaseObjectCapability([Const] DOMString capability);
|
||||
[Const, Ref] DOMString GetRequiredBaseObjectCapability();
|
||||
@@ -1211,6 +1211,12 @@ interface InstructionMetadata {
|
||||
[Ref] InstructionMetadata MarkAsComplex();
|
||||
|
||||
[Ref] ExtraInformation GetCodeExtraInformation();
|
||||
|
||||
[Ref] ExtraInformation SetFunctionName([Const] DOMString functionName);
|
||||
|
||||
[Ref] InstructionMetadata SetIncludeFile([Const] DOMString includeFile);
|
||||
[Ref] InstructionMetadata AddIncludeFile([Const] DOMString includeFile);
|
||||
[Const, Ref] VectorString GetIncludeFiles();
|
||||
};
|
||||
|
||||
interface ExpressionMetadata {
|
||||
@@ -1246,11 +1252,18 @@ interface ExpressionMetadata {
|
||||
[Const] DOMString type, [Const] DOMString supplementaryInformation);
|
||||
[Ref] ExpressionMetadata SetDefaultValue([Const] DOMString defaultValue);
|
||||
[Ref] ExpressionMetadata SetParameterLongDescription([Const] DOMString longDescription);
|
||||
[Ref] ExpressionMetadata SetParameterExtraInfo([Const] DOMString extraInfo);
|
||||
|
||||
[Ref] ExpressionMetadata SetRequiresBaseObjectCapability([Const] DOMString capability);
|
||||
[Const, Ref] DOMString GetRequiredBaseObjectCapability();
|
||||
|
||||
[Ref] ExpressionCodeGenerationInformation GetCodeExtraInformation();
|
||||
|
||||
[Ref] ExpressionCodeGenerationInformation SetFunctionName([Const] DOMString functionName);
|
||||
|
||||
[Ref] ExpressionMetadata SetIncludeFile([Const] DOMString includeFile);
|
||||
[Ref] ExpressionMetadata AddIncludeFile([Const] DOMString includeFile);
|
||||
[Const, Ref] VectorString GetIncludeFiles();
|
||||
};
|
||||
|
||||
interface MultipleInstructionMetadata {
|
||||
@@ -1262,8 +1275,9 @@ interface MultipleInstructionMetadata {
|
||||
[Const] DOMString type, [Const] DOMString supplementaryInformation);
|
||||
[Ref] MultipleInstructionMetadata SetDefaultValue([Const] DOMString defaultValue);
|
||||
[Ref] MultipleInstructionMetadata SetParameterLongDescription([Const] DOMString longDescription);
|
||||
[Ref] MultipleInstructionMetadata SetParameterExtraInfo([Const] DOMString extraInfo);
|
||||
|
||||
[Ref] MultipleInstructionMetadata UseStandardParameters([Const] DOMString type);
|
||||
[Ref] MultipleInstructionMetadata UseStandardParameters([Const] DOMString type, [Const] optional DOMString typeExtraInfo = "");
|
||||
|
||||
[Ref] MultipleInstructionMetadata SetHidden();
|
||||
|
||||
@@ -1272,10 +1286,12 @@ interface MultipleInstructionMetadata {
|
||||
|
||||
[Ref] MultipleInstructionMetadata SetIncludeFile([Const] DOMString includeFile);
|
||||
[Ref] MultipleInstructionMetadata AddIncludeFile([Const] DOMString includeFile);
|
||||
[Const, Ref] VectorString GetIncludeFiles();
|
||||
|
||||
[Ref] MultipleInstructionMetadata MarkAsSimple();
|
||||
[Ref] MultipleInstructionMetadata MarkAsAdvanced();
|
||||
[Ref] MultipleInstructionMetadata MarkAsComplex();
|
||||
[Ref] MultipleInstructionMetadata SetPrivate();
|
||||
};
|
||||
|
||||
interface DependencyMetadata {
|
||||
@@ -1317,6 +1333,10 @@ interface ParameterMetadata {
|
||||
[Ref] ParameterMetadata SetCodeOnly(boolean codeOnly_);
|
||||
[Const, Ref] DOMString GetDefaultValue();
|
||||
[Ref] ParameterMetadata SetDefaultValue([Const] DOMString defaultValue_);
|
||||
|
||||
[Ref] ParameterMetadata SetValueTypeMetadata([Const, Ref] ValueTypeMetadata type);
|
||||
[Const, Ref] ValueTypeMetadata GetValueTypeMetadata();
|
||||
|
||||
boolean STATIC_IsObject([Const] DOMString param);
|
||||
boolean STATIC_IsBehavior([Const] DOMString param);
|
||||
boolean STATIC_IsExpression([Const] DOMString type_, [Const] DOMString parameterType);
|
||||
@@ -1325,6 +1345,33 @@ interface ParameterMetadata {
|
||||
void UnserializeFrom([Const, Ref] SerializerElement element);
|
||||
};
|
||||
|
||||
interface ValueTypeMetadata {
|
||||
void ValueTypeMetadata();
|
||||
|
||||
[Const, Ref] DOMString GetName();
|
||||
[Ref] ValueTypeMetadata SetName([Const] DOMString name_);
|
||||
[Const, Ref] DOMString GetExtraInfo();
|
||||
[Ref] ValueTypeMetadata SetExtraInfo([Const] DOMString extraInfo_);
|
||||
boolean IsOptional();
|
||||
[Ref] ValueTypeMetadata SetOptional(boolean optional_);
|
||||
[Const, Ref] DOMString GetDefaultValue();
|
||||
[Ref] ValueTypeMetadata SetDefaultValue([Const] DOMString defaultValue_);
|
||||
|
||||
boolean IsObject();
|
||||
boolean IsBehavior();
|
||||
boolean IsNumber();
|
||||
boolean IsString();
|
||||
boolean IsVariable();
|
||||
|
||||
boolean STATIC_IsTypeObject([Const] DOMString parameterType);
|
||||
boolean STATIC_IsTypeBehavior([Const] DOMString parameterType);
|
||||
boolean STATIC_IsTypeExpression([Const] DOMString type, [Const] DOMString parameterType);
|
||||
[Const, Ref] DOMString STATIC_GetPrimitiveValueType([Const] DOMString parameterType);
|
||||
|
||||
void SerializeTo([Ref] SerializerElement element);
|
||||
void UnserializeFrom([Const, Ref] SerializerElement element);
|
||||
};
|
||||
|
||||
interface VectorParameterMetadata {
|
||||
void VectorParameterMetadata();
|
||||
|
||||
@@ -1343,7 +1390,7 @@ interface ParameterMetadataTools {
|
||||
};
|
||||
|
||||
interface EventsFunctionTools {
|
||||
void STATIC_FreeEventsFunctionToObjectsContainer([Ref] Project project, [Const, Ref] EventsFunction eventsFunction, [Ref] ObjectsContainer outputGlobalObjectsContainer, [Ref] ObjectsContainer outputObjectsContainer);
|
||||
void STATIC_FreeEventsFunctionToObjectsContainer([Ref] Project project, [Const, Ref] EventsFunctionsContainer functionsContainer, [Const, Ref] EventsFunction eventsFunction, [Ref] ObjectsContainer outputGlobalObjectsContainer, [Ref] ObjectsContainer outputObjectsContainer);
|
||||
void STATIC_BehaviorEventsFunctionToObjectsContainer([Ref] Project project, [Const, Ref] EventsBasedBehavior eventsBasedBehavior, [Const, Ref] EventsFunction eventsFunction, [Ref] ObjectsContainer outputGlobalObjectsContainer, [Ref] ObjectsContainer outputObjectsContainer);
|
||||
void STATIC_ObjectEventsFunctionToObjectsContainer([Ref] Project project, [Const, Ref] EventsBasedObject eventsBasedObject, [Const, Ref] EventsFunction eventsFunction, [Ref] ObjectsContainer outputGlobalObjectsContainer, [Ref] ObjectsContainer outputObjectsContainer);
|
||||
};
|
||||
@@ -2243,7 +2290,8 @@ enum EventsFunction_FunctionType {
|
||||
"EventsFunction::Action",
|
||||
"EventsFunction::Condition",
|
||||
"EventsFunction::Expression",
|
||||
"EventsFunction::StringExpression"
|
||||
"EventsFunction::ExpressionAndCondition",
|
||||
"EventsFunction::ActionWithOperator"
|
||||
};
|
||||
|
||||
interface EventsFunction {
|
||||
@@ -2260,13 +2308,21 @@ interface EventsFunction {
|
||||
[Const, Ref] DOMString GetSentence();
|
||||
[Ref] EventsFunction SetGroup([Const] DOMString group);
|
||||
[Const, Ref] DOMString GetGroup();
|
||||
[Ref] EventsFunction SetGetterName([Const] DOMString group);
|
||||
[Const, Ref] DOMString GetGetterName();
|
||||
[Ref] EventsFunction SetExpressionType([Const, Ref] ValueTypeMetadata type);
|
||||
[Const, Ref] ValueTypeMetadata GetExpressionType();
|
||||
[Ref] EventsFunction SetPrivate(boolean isPrivate);
|
||||
boolean IsPrivate();
|
||||
boolean IsAction();
|
||||
boolean IsExpression();
|
||||
boolean IsCondition();
|
||||
[Ref] EventsFunction SetFunctionType(EventsFunction_FunctionType type);
|
||||
EventsFunction_FunctionType GetFunctionType();
|
||||
|
||||
[Ref] EventsList GetEvents();
|
||||
[Ref] VectorParameterMetadata GetParameters();
|
||||
[Const, Ref] VectorParameterMetadata GetParametersForEvents([Const, Ref] EventsFunctionsContainer functionsContainer);
|
||||
[Ref] ObjectGroupsContainer GetObjectGroups();
|
||||
|
||||
void SerializeTo([Ref] SerializerElement element);
|
||||
@@ -2947,7 +3003,7 @@ interface ObjectCodeGenerator {
|
||||
[Prefix="gdjs::"]
|
||||
interface EventsFunctionsExtensionCodeGenerator {
|
||||
void EventsFunctionsExtensionCodeGenerator([Ref] Project project);
|
||||
[Const, Value] DOMString GenerateFreeEventsFunctionCompleteCode([Const, Ref] EventsFunction eventsFunction, [Const] DOMString codeNamespac, [Ref] SetString includes, boolean compilationForRuntime);
|
||||
[Const, Value] DOMString GenerateFreeEventsFunctionCompleteCode([Const, Ref] EventsFunctionsExtension extension, [Const, Ref] EventsFunction eventsFunction, [Const] DOMString codeNamespac, [Ref] SetString includes, boolean compilationForRuntime);
|
||||
};
|
||||
|
||||
[Prefix="gdjs::"]
|
||||
|
@@ -511,6 +511,11 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
|
||||
#define STATIC_IsObject IsObject
|
||||
#define STATIC_IsBehavior IsBehavior
|
||||
#define STATIC_IsExpression IsExpression
|
||||
#define STATIC_IsTypeObject IsTypeObject
|
||||
#define STATIC_IsTypeBehavior IsTypeBehavior
|
||||
#define STATIC_IsTypeExpression IsTypeExpression
|
||||
#define STATIC_GetExpressionValueType GetExpressionValueType
|
||||
#define STATIC_GetPrimitiveValueType GetPrimitiveValueType
|
||||
#define STATIC_Get Get
|
||||
#define STATIC_GetAllUseless GetAllUseless
|
||||
#define STATIC_RemoveAllUseless RemoveAllUseless
|
||||
|
@@ -17,8 +17,10 @@ function generateCompiledEventsForEventsFunction(
|
||||
new gd.EventsFunctionsExtensionCodeGenerator(project);
|
||||
|
||||
const includeFiles = new gd.SetString();
|
||||
const extension = new gd.EventsFunctionsExtension();
|
||||
const code =
|
||||
eventsFunctionsExtensionCodeGenerator.generateFreeEventsFunctionCompleteCode(
|
||||
extension,
|
||||
eventsFunction,
|
||||
namespace,
|
||||
includeFiles,
|
||||
@@ -26,6 +28,7 @@ function generateCompiledEventsForEventsFunction(
|
||||
);
|
||||
|
||||
eventsFunctionsExtensionCodeGenerator.delete();
|
||||
extension.delete();
|
||||
includeFiles.delete();
|
||||
|
||||
if (logCode) console.log(code);
|
||||
|
@@ -2468,8 +2468,11 @@ describe('libGD.js', function () {
|
||||
expect(parametersLister.getParametersAndTypes().get('MyObject')).toBe(
|
||||
'object'
|
||||
);
|
||||
// There are a lot of parameter definitions with 'expression' instead
|
||||
// of 'number'. They both means the same thing but 'expression' is
|
||||
// deprecated.
|
||||
expect(parametersLister.getParametersAndTypes().get('300')).toBe(
|
||||
'expression'
|
||||
'number'
|
||||
);
|
||||
|
||||
project.delete();
|
||||
|
@@ -475,10 +475,12 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
gd.asRepeatEvent(evt).getActions().insert(action2, 1);
|
||||
|
||||
const namespace = 'gdjs.eventsFunction.myTest';
|
||||
const extension = new gd.EventsFunctionsExtension();
|
||||
const eventsFunctionsExtensionCodeGenerator =
|
||||
new gd.EventsFunctionsExtensionCodeGenerator(project);
|
||||
const code =
|
||||
eventsFunctionsExtensionCodeGenerator.generateFreeEventsFunctionCompleteCode(
|
||||
extension,
|
||||
eventsFunction,
|
||||
namespace,
|
||||
includeFiles,
|
||||
@@ -531,6 +533,7 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
|
||||
condition.delete();
|
||||
action.delete();
|
||||
extension.delete();
|
||||
});
|
||||
|
||||
it('can generate code for an events function, with groups', function () {
|
||||
@@ -583,6 +586,7 @@ describe('libGD.js - GDJS related tests', function () {
|
||||
new gd.EventsFunctionsExtensionCodeGenerator(project);
|
||||
const code =
|
||||
eventsFunctionsExtensionCodeGenerator.generateFreeEventsFunctionCompleteCode(
|
||||
new gd.EventsFunctionsExtension(),
|
||||
eventsFunction,
|
||||
namespace,
|
||||
includeFiles,
|
||||
|
@@ -82,7 +82,7 @@ declare type gdEmscriptenObject = {
|
||||
fs.writeFileSync(
|
||||
'types/eventsfunction_functiontype.js',
|
||||
`// Automatically generated by GDevelop.js/scripts/generate-types.js
|
||||
type EventsFunction_FunctionType = 0 | 1 | 2 | 3`
|
||||
type EventsFunction_FunctionType = 0 | 1 | 2 | 3 | 4`
|
||||
);
|
||||
shell.sed(
|
||||
'-i',
|
||||
@@ -92,7 +92,8 @@ type EventsFunction_FunctionType = 0 | 1 | 2 | 3`
|
||||
' static Action: 0;',
|
||||
' static Condition: 1;',
|
||||
' static Expression: 2;',
|
||||
' static StringExpression: 3;',
|
||||
' static ExpressionAndCondition: 3;',
|
||||
' static ActionWithOperator: 4;',
|
||||
].join('\n'),
|
||||
'types/gdeventsfunction.js'
|
||||
);
|
||||
|
@@ -1,2 +1,2 @@
|
||||
// Automatically generated by GDevelop.js/scripts/generate-types.js
|
||||
type EventsFunction_FunctionType = 0 | 1 | 2 | 3
|
||||
type EventsFunction_FunctionType = 0 | 1 | 2 | 3 | 4
|
@@ -3,7 +3,8 @@ declare class gdEventsFunction {
|
||||
static Action: 0;
|
||||
static Condition: 1;
|
||||
static Expression: 2;
|
||||
static StringExpression: 3;
|
||||
static ExpressionAndCondition: 3;
|
||||
static ActionWithOperator: 4;
|
||||
constructor(): void;
|
||||
clone(): gdEventsFunction;
|
||||
setDescription(description: string): gdEventsFunction;
|
||||
@@ -16,12 +17,20 @@ declare class gdEventsFunction {
|
||||
getSentence(): string;
|
||||
setGroup(group: string): gdEventsFunction;
|
||||
getGroup(): string;
|
||||
setGetterName(group: string): gdEventsFunction;
|
||||
getGetterName(): string;
|
||||
setExpressionType(type: gdValueTypeMetadata): gdEventsFunction;
|
||||
getExpressionType(): gdValueTypeMetadata;
|
||||
setPrivate(isPrivate: boolean): gdEventsFunction;
|
||||
isPrivate(): boolean;
|
||||
isAction(): boolean;
|
||||
isExpression(): boolean;
|
||||
isCondition(): boolean;
|
||||
setFunctionType(type: EventsFunction_FunctionType): gdEventsFunction;
|
||||
getFunctionType(): EventsFunction_FunctionType;
|
||||
getEvents(): gdEventsList;
|
||||
getParameters(): gdVectorParameterMetadata;
|
||||
getParametersForEvents(functionsContainer: gdEventsFunctionsContainer): gdVectorParameterMetadata;
|
||||
getObjectGroups(): gdObjectGroupsContainer;
|
||||
serializeTo(element: gdSerializerElement): void;
|
||||
unserializeFrom(project: gdProject, element: gdSerializerElement): void;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// Automatically generated by GDevelop.js/scripts/generate-types.js
|
||||
declare class gdEventsFunctionsExtensionCodeGenerator {
|
||||
constructor(project: gdProject): void;
|
||||
generateFreeEventsFunctionCompleteCode(eventsFunction: gdEventsFunction, codeNamespac: string, includes: gdSetString, compilationForRuntime: boolean): string;
|
||||
generateFreeEventsFunctionCompleteCode(extension: gdEventsFunctionsExtension, eventsFunction: gdEventsFunction, codeNamespac: string, includes: gdSetString, compilationForRuntime: boolean): string;
|
||||
delete(): void;
|
||||
ptr: number;
|
||||
};
|
@@ -1,6 +1,6 @@
|
||||
// Automatically generated by GDevelop.js/scripts/generate-types.js
|
||||
declare class gdEventsFunctionTools {
|
||||
static freeEventsFunctionToObjectsContainer(project: gdProject, eventsFunction: gdEventsFunction, outputGlobalObjectsContainer: gdObjectsContainer, outputObjectsContainer: gdObjectsContainer): void;
|
||||
static freeEventsFunctionToObjectsContainer(project: gdProject, functionsContainer: gdEventsFunctionsContainer, eventsFunction: gdEventsFunction, outputGlobalObjectsContainer: gdObjectsContainer, outputObjectsContainer: gdObjectsContainer): void;
|
||||
static behaviorEventsFunctionToObjectsContainer(project: gdProject, eventsBasedBehavior: gdEventsBasedBehavior, eventsFunction: gdEventsFunction, outputGlobalObjectsContainer: gdObjectsContainer, outputObjectsContainer: gdObjectsContainer): void;
|
||||
static objectEventsFunctionToObjectsContainer(project: gdProject, eventsBasedObject: gdEventsBasedObject, eventsFunction: gdEventsFunction, outputGlobalObjectsContainer: gdObjectsContainer, outputObjectsContainer: gdObjectsContainer): void;
|
||||
delete(): void;
|
||||
|
@@ -18,9 +18,14 @@ declare class gdExpressionMetadata {
|
||||
addCodeOnlyParameter(type: string, supplementaryInformation: string): gdExpressionMetadata;
|
||||
setDefaultValue(defaultValue: string): gdExpressionMetadata;
|
||||
setParameterLongDescription(longDescription: string): gdExpressionMetadata;
|
||||
setParameterExtraInfo(extraInfo: string): gdExpressionMetadata;
|
||||
setRequiresBaseObjectCapability(capability: string): gdExpressionMetadata;
|
||||
getRequiredBaseObjectCapability(): string;
|
||||
getCodeExtraInformation(): gdExpressionCodeGenerationInformation;
|
||||
setFunctionName(functionName: string): gdExpressionCodeGenerationInformation;
|
||||
setIncludeFile(includeFile: string): gdExpressionMetadata;
|
||||
addIncludeFile(includeFile: string): gdExpressionMetadata;
|
||||
getIncludeFiles(): gdVectorString;
|
||||
delete(): void;
|
||||
ptr: number;
|
||||
};
|
@@ -26,14 +26,18 @@ declare class gdInstructionMetadata {
|
||||
setDefaultValue(defaultValue: string): gdInstructionMetadata;
|
||||
setParameterLongDescription(longDescription: string): gdInstructionMetadata;
|
||||
setParameterExtraInfo(extraInfo: string): gdInstructionMetadata;
|
||||
useStandardOperatorParameters(type: string): gdInstructionMetadata;
|
||||
useStandardRelationalOperatorParameters(type: string): gdInstructionMetadata;
|
||||
useStandardOperatorParameters(type: string, typeExtraInfo?: string): gdInstructionMetadata;
|
||||
useStandardRelationalOperatorParameters(type: string, typeExtraInfo?: string): gdInstructionMetadata;
|
||||
setRequiresBaseObjectCapability(capability: string): gdInstructionMetadata;
|
||||
getRequiredBaseObjectCapability(): string;
|
||||
markAsSimple(): gdInstructionMetadata;
|
||||
markAsAdvanced(): gdInstructionMetadata;
|
||||
markAsComplex(): gdInstructionMetadata;
|
||||
getCodeExtraInformation(): gdExtraInformation;
|
||||
setFunctionName(functionName: string): gdExtraInformation;
|
||||
setIncludeFile(includeFile: string): gdInstructionMetadata;
|
||||
addIncludeFile(includeFile: string): gdInstructionMetadata;
|
||||
getIncludeFiles(): gdVectorString;
|
||||
delete(): void;
|
||||
ptr: number;
|
||||
};
|
@@ -4,15 +4,18 @@ declare class gdMultipleInstructionMetadata {
|
||||
addCodeOnlyParameter(type: string, supplementaryInformation: string): gdMultipleInstructionMetadata;
|
||||
setDefaultValue(defaultValue: string): gdMultipleInstructionMetadata;
|
||||
setParameterLongDescription(longDescription: string): gdMultipleInstructionMetadata;
|
||||
useStandardParameters(type: string): gdMultipleInstructionMetadata;
|
||||
setParameterExtraInfo(extraInfo: string): gdMultipleInstructionMetadata;
|
||||
useStandardParameters(type: string, typeExtraInfo?: string): gdMultipleInstructionMetadata;
|
||||
setHidden(): gdMultipleInstructionMetadata;
|
||||
setFunctionName(functionName: string): gdMultipleInstructionMetadata;
|
||||
setGetter(getter: string): gdMultipleInstructionMetadata;
|
||||
setIncludeFile(includeFile: string): gdMultipleInstructionMetadata;
|
||||
addIncludeFile(includeFile: string): gdMultipleInstructionMetadata;
|
||||
getIncludeFiles(): gdVectorString;
|
||||
markAsSimple(): gdMultipleInstructionMetadata;
|
||||
markAsAdvanced(): gdMultipleInstructionMetadata;
|
||||
markAsComplex(): gdMultipleInstructionMetadata;
|
||||
setPrivate(): gdMultipleInstructionMetadata;
|
||||
delete(): void;
|
||||
ptr: number;
|
||||
};
|
@@ -17,6 +17,8 @@ declare class gdParameterMetadata {
|
||||
setCodeOnly(codeOnly_: boolean): gdParameterMetadata;
|
||||
getDefaultValue(): string;
|
||||
setDefaultValue(defaultValue_: string): gdParameterMetadata;
|
||||
setValueTypeMetadata(type: gdValueTypeMetadata): gdParameterMetadata;
|
||||
getValueTypeMetadata(): gdValueTypeMetadata;
|
||||
static isObject(param: string): boolean;
|
||||
static isBehavior(param: string): boolean;
|
||||
static isExpression(type_: string, parameterType: string): boolean;
|
||||
|
25
GDevelop.js/types/gdvaluetypemetadata.js
Normal file
25
GDevelop.js/types/gdvaluetypemetadata.js
Normal file
@@ -0,0 +1,25 @@
|
||||
// Automatically generated by GDevelop.js/scripts/generate-types.js
|
||||
declare class gdValueTypeMetadata {
|
||||
constructor(): void;
|
||||
getName(): string;
|
||||
setName(name_: string): gdValueTypeMetadata;
|
||||
getExtraInfo(): string;
|
||||
setExtraInfo(extraInfo_: string): gdValueTypeMetadata;
|
||||
isOptional(): boolean;
|
||||
setOptional(optional_: boolean): gdValueTypeMetadata;
|
||||
getDefaultValue(): string;
|
||||
setDefaultValue(defaultValue_: string): gdValueTypeMetadata;
|
||||
isObject(): boolean;
|
||||
isBehavior(): boolean;
|
||||
isNumber(): boolean;
|
||||
isString(): boolean;
|
||||
isVariable(): boolean;
|
||||
static isTypeObject(parameterType: string): boolean;
|
||||
static isTypeBehavior(parameterType: string): boolean;
|
||||
static isTypeExpression(type: string, parameterType: string): boolean;
|
||||
static getPrimitiveValueType(parameterType: string): string;
|
||||
serializeTo(element: gdSerializerElement): void;
|
||||
unserializeFrom(element: gdSerializerElement): void;
|
||||
delete(): void;
|
||||
ptr: number;
|
||||
};
|
@@ -119,6 +119,7 @@ declare class libGDevelop {
|
||||
MultipleInstructionMetadata: Class<gdMultipleInstructionMetadata>;
|
||||
DependencyMetadata: Class<gdDependencyMetadata>;
|
||||
ParameterMetadata: Class<gdParameterMetadata>;
|
||||
ValueTypeMetadata: Class<gdValueTypeMetadata>;
|
||||
VectorParameterMetadata: Class<gdVectorParameterMetadata>;
|
||||
ParameterMetadataTools: Class<gdParameterMetadataTools>;
|
||||
EventsFunctionTools: Class<gdEventsFunctionTools>;
|
||||
|
@@ -5,8 +5,6 @@ import { I18n } from '@lingui/react';
|
||||
import { type I18n as I18nType } from '@lingui/core';
|
||||
import * as React from 'react';
|
||||
import { Column, Line, Spacer } from '../../UI/Grid';
|
||||
import SelectField from '../../UI/SelectField';
|
||||
import SelectOption from '../../UI/SelectOption';
|
||||
import { mapVector } from '../../Utils/MapFor';
|
||||
import RaisedButton from '../../UI/RaisedButton';
|
||||
import IconButton from '../../UI/IconButton';
|
||||
@@ -17,8 +15,6 @@ import HelpButton from '../../UI/HelpButton';
|
||||
import SemiControlledTextField from '../../UI/SemiControlledTextField';
|
||||
import MiniToolbar, { MiniToolbarText } from '../../UI/MiniToolbar';
|
||||
import { showWarningBox } from '../../UI/Messages/MessageBox';
|
||||
import ObjectTypeSelector from '../../ObjectTypeSelector';
|
||||
import BehaviorTypeSelector from '../../BehaviorTypeSelector';
|
||||
import {
|
||||
isBehaviorLifecycleEventsFunction,
|
||||
isExtensionLifecycleEventsFunction,
|
||||
@@ -26,10 +22,10 @@ import {
|
||||
import { ParametersIndexOffsets } from '../../EventsFunctionsExtensionsLoader';
|
||||
import Add from '@material-ui/icons/Add';
|
||||
import DismissableAlertMessage from '../../UI/DismissableAlertMessage';
|
||||
import { ColumnStackLayout, ResponsiveLineStackLayout } from '../../UI/Layout';
|
||||
import { ColumnStackLayout } from '../../UI/Layout';
|
||||
import { getLastObjectParameterObjectType } from '../../EventsSheet/ParameterFields/ParameterMetadataTools';
|
||||
import StringArrayEditor from '../../StringArrayEditor';
|
||||
import newNameGenerator from '../../Utils/NewNameGenerator';
|
||||
import ValueTypeEditor from './ValueTypeEditor';
|
||||
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
@@ -38,6 +34,7 @@ type Props = {|
|
||||
eventsFunction: gdEventsFunction,
|
||||
eventsBasedBehavior: ?gdEventsBasedBehavior,
|
||||
eventsBasedObject: ?gdEventsBasedObject,
|
||||
eventsFunctionsContainer: ?gdEventsFunctionsContainer,
|
||||
onParametersUpdated: () => void,
|
||||
helpPagePath?: string,
|
||||
freezeParameters?: boolean,
|
||||
@@ -97,27 +94,6 @@ const validateParameterName = (i18n: I18nType, newName: string) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
const getExtraInfoArray = (parameter: gdParameterMetadata) => {
|
||||
const extraInfoJson = parameter.getExtraInfo();
|
||||
let array = [];
|
||||
try {
|
||||
if (extraInfoJson !== '') array = JSON.parse(extraInfoJson);
|
||||
if (!Array.isArray(array)) array = [];
|
||||
} catch (e) {
|
||||
console.error('Cannot parse parameter extraInfo: ', e);
|
||||
}
|
||||
|
||||
return array;
|
||||
};
|
||||
|
||||
const getIdentifierScope = (scopedIdentifier: string) =>
|
||||
scopedIdentifier.startsWith('object') ? 'object' : 'scene';
|
||||
|
||||
const getIdentifierName = (scopedIdentifier: string) =>
|
||||
scopedIdentifier.startsWith('object')
|
||||
? scopedIdentifier.substring('object'.length)
|
||||
: scopedIdentifier.substring('scene'.length);
|
||||
|
||||
export default class EventsFunctionParametersEditor extends React.Component<
|
||||
Props,
|
||||
State
|
||||
@@ -244,11 +220,11 @@ export default class EventsFunctionParametersEditor extends React.Component<
|
||||
eventsFunction,
|
||||
eventsBasedBehavior,
|
||||
eventsBasedObject,
|
||||
eventsFunctionsContainer,
|
||||
freezeParameters,
|
||||
helpPagePath,
|
||||
} = this.props;
|
||||
|
||||
const parameters = eventsFunction.getParameters();
|
||||
const isABehaviorLifecycleEventsFunction =
|
||||
!!eventsBasedBehavior &&
|
||||
isBehaviorLifecycleEventsFunction(eventsFunction.getName());
|
||||
@@ -292,29 +268,48 @@ export default class EventsFunctionParametersEditor extends React.Component<
|
||||
);
|
||||
}
|
||||
|
||||
const parameters =
|
||||
eventsFunctionsContainer &&
|
||||
eventsFunction.getFunctionType() === gd.EventsFunction.ActionWithOperator
|
||||
? eventsFunction.getParametersForEvents(eventsFunctionsContainer)
|
||||
: eventsFunction.getParameters();
|
||||
|
||||
const firstParameterIndex = eventsBasedBehavior
|
||||
? 2
|
||||
: eventsBasedObject
|
||||
? 1
|
||||
: 0;
|
||||
const isParameterDisabled = index => {
|
||||
return (
|
||||
!!freezeParameters ||
|
||||
(!!eventsBasedBehavior && index < 2) ||
|
||||
(!!eventsBasedObject && index < 1)
|
||||
eventsFunction.getFunctionType() ===
|
||||
gd.EventsFunction.ActionWithOperator ||
|
||||
freezeParameters ||
|
||||
index < firstParameterIndex
|
||||
);
|
||||
};
|
||||
const isParameterDescriptionAndTypeShown = index => {
|
||||
// The first two parameters of a behavior method should not be changed at all,
|
||||
// so we even hide their description and type to avoid cluttering the interface.
|
||||
// Same thing for an object which has mandatory Object parameter.
|
||||
return (
|
||||
(!eventsBasedBehavior && !eventsBasedObject) ||
|
||||
(!!eventsBasedBehavior && index >= 2) ||
|
||||
(!!eventsBasedObject && index >= 1)
|
||||
);
|
||||
// The first two parameters of a behavior method should not be changed at all,
|
||||
// so we even hide their description and type to avoid cluttering the interface.
|
||||
// Same thing for an object which has mandatory Object parameter.
|
||||
const typeShownFirstIndex = firstParameterIndex;
|
||||
const isParameterTypeShown = index => {
|
||||
return index >= typeShownFirstIndex;
|
||||
};
|
||||
// The first two parameters of a behavior method should not be changed at all,
|
||||
// so we even hide their description and type to avoid cluttering the interface.
|
||||
// Same thing for an object which has mandatory Object parameter.
|
||||
const labelShownFirstIndex =
|
||||
firstParameterIndex +
|
||||
(eventsFunction.getFunctionType() === gd.EventsFunction.ActionWithOperator
|
||||
? 1
|
||||
: 0);
|
||||
const isParameterDescriptionShown = index => {
|
||||
return index >= labelShownFirstIndex;
|
||||
};
|
||||
const isParameterLongDescriptionShown = (parameter, index): boolean => {
|
||||
if (!isParameterDescriptionAndTypeShown(index)) return false;
|
||||
|
||||
return (
|
||||
!!parameter.getLongDescription() ||
|
||||
!!this.state.longDescriptionShownIndexes[index]
|
||||
isParameterDescriptionShown(index) &&
|
||||
(!!parameter.getLongDescription() ||
|
||||
!!this.state.longDescriptionShownIndexes[index])
|
||||
);
|
||||
};
|
||||
const parametersIndexOffset = eventsBasedBehavior
|
||||
@@ -406,221 +401,19 @@ export default class EventsFunctionParametersEditor extends React.Component<
|
||||
</MiniToolbar>
|
||||
<Line>
|
||||
<ColumnStackLayout expand>
|
||||
<ResponsiveLineStackLayout noMargin>
|
||||
{isParameterDescriptionAndTypeShown(i) && (
|
||||
<SelectField
|
||||
floatingLabelText={<Trans>Type</Trans>}
|
||||
value={parameter.getType()}
|
||||
onChange={(e, i, value: string) => {
|
||||
parameter.setType(value);
|
||||
parameter.setOptional(false);
|
||||
parameter.setDefaultValue('');
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
disabled={isParameterDisabled(i)}
|
||||
fullWidth
|
||||
>
|
||||
<SelectOption
|
||||
value="objectList"
|
||||
primaryText={t`Objects`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="behavior"
|
||||
primaryText={t`Behavior (for the previous object)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="expression"
|
||||
primaryText={t`Number`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="string"
|
||||
primaryText={t`String (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="stringWithSelector"
|
||||
primaryText={t`String from a list of options (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="key"
|
||||
primaryText={t`Keyboard Key (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="mouse"
|
||||
primaryText={t`Mouse button (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="color"
|
||||
primaryText={t`Color (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="layer"
|
||||
primaryText={t`Layer (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="sceneName"
|
||||
primaryText={t`Scene name (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="yesorno"
|
||||
primaryText={t`Yes or No (boolean)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="trueorfalse"
|
||||
primaryText={t`True or False (boolean)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="objectPointName"
|
||||
primaryText={t`Object point (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="objectAnimationName"
|
||||
primaryText={t`Object animation (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="identifier"
|
||||
primaryText={t`Identifier (text)`}
|
||||
/>
|
||||
</SelectField>
|
||||
)}
|
||||
{gd.ParameterMetadata.isObject(
|
||||
parameter.getType()
|
||||
) && (
|
||||
<ObjectTypeSelector
|
||||
project={project}
|
||||
value={parameter.getExtraInfo()}
|
||||
onChange={(value: string) => {
|
||||
parameter.setExtraInfo(value);
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
disabled={isParameterDisabled(i)}
|
||||
/>
|
||||
)}
|
||||
{parameter.getType() === 'behavior' && (
|
||||
<BehaviorTypeSelector
|
||||
project={project}
|
||||
objectType={getLastObjectParameterObjectType(
|
||||
parameters,
|
||||
i
|
||||
)}
|
||||
value={parameter.getExtraInfo()}
|
||||
onChange={(value: string) => {
|
||||
parameter.setExtraInfo(value);
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
disabled={isParameterDisabled(i)}
|
||||
/>
|
||||
)}
|
||||
{parameter.getType() === 'yesorno' && (
|
||||
<SelectField
|
||||
floatingLabelText={<Trans>Default value</Trans>}
|
||||
value={
|
||||
parameter.getDefaultValue() === 'yes'
|
||||
? 'yes'
|
||||
: 'no'
|
||||
}
|
||||
onChange={(e, i, value) => {
|
||||
parameter.setOptional(true);
|
||||
parameter.setDefaultValue(value);
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<SelectOption
|
||||
value="yes"
|
||||
primaryText={t`Yes`}
|
||||
/>
|
||||
<SelectOption value="no" primaryText={t`No`} />
|
||||
</SelectField>
|
||||
)}
|
||||
{parameter.getType() === 'trueorfalse' && (
|
||||
<SelectField
|
||||
floatingLabelText={<Trans>Default value</Trans>}
|
||||
value={
|
||||
parameter.getDefaultValue() === 'True'
|
||||
? 'True'
|
||||
: 'False'
|
||||
}
|
||||
onChange={(e, i, value) => {
|
||||
parameter.setOptional(true);
|
||||
parameter.setDefaultValue(value);
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<SelectOption
|
||||
value="True"
|
||||
primaryText={t`True`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="False"
|
||||
primaryText={t`False`}
|
||||
/>
|
||||
</SelectField>
|
||||
)}
|
||||
{parameter.getType() === 'identifier' && (
|
||||
<SelectField
|
||||
floatingLabelText={<Trans>Scope</Trans>}
|
||||
value={getIdentifierScope(
|
||||
parameter.getExtraInfo()
|
||||
)}
|
||||
onChange={(e, i, value) => {
|
||||
const identifierName = getIdentifierName(
|
||||
parameter.getExtraInfo()
|
||||
);
|
||||
parameter.setExtraInfo(
|
||||
value + identifierName
|
||||
);
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<SelectOption
|
||||
value="scene"
|
||||
primaryText={t`Scene`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="object"
|
||||
primaryText={t`Object`}
|
||||
/>
|
||||
</SelectField>
|
||||
)}
|
||||
{parameter.getType() === 'identifier' && (
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={
|
||||
<Trans>Identifier name</Trans>
|
||||
}
|
||||
floatingLabelFixed
|
||||
value={getIdentifierName(
|
||||
parameter.getExtraInfo()
|
||||
)}
|
||||
onChange={value => {
|
||||
const scope = getIdentifierScope(
|
||||
parameter.getExtraInfo()
|
||||
);
|
||||
parameter.setExtraInfo(scope + value);
|
||||
this.forceUpdate();
|
||||
this.props.onParametersUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
</ResponsiveLineStackLayout>
|
||||
{parameter.getType() === 'stringWithSelector' && (
|
||||
<StringArrayEditor
|
||||
extraInfo={getExtraInfoArray(parameter)}
|
||||
setExtraInfo={this._setStringSelectorExtraInfo(
|
||||
parameter
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
{isParameterDescriptionAndTypeShown(i) && (
|
||||
<ValueTypeEditor
|
||||
project={project}
|
||||
valueTypeMetadata={parameter.getValueTypeMetadata()}
|
||||
disabled={isParameterDisabled(i)}
|
||||
isTypeSelectorShown={isParameterTypeShown(i)}
|
||||
onTypeUpdated={() =>
|
||||
this.props.onParametersUpdated()
|
||||
}
|
||||
getLastObjectParameterObjectType={() =>
|
||||
getLastObjectParameterObjectType(parameters, i)
|
||||
}
|
||||
/>
|
||||
{isParameterDescriptionShown(i) && (
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Label</Trans>}
|
||||
@@ -632,7 +425,8 @@ export default class EventsFunctionParametersEditor extends React.Component<
|
||||
}}
|
||||
fullWidth
|
||||
disabled={
|
||||
false /* Label, if shown, can always be changed */
|
||||
/* When parameter are freezed, long description (if shown) can always be changed */
|
||||
isParameterDisabled(i) && !freezeParameters
|
||||
}
|
||||
/>
|
||||
)}
|
||||
@@ -651,7 +445,8 @@ export default class EventsFunctionParametersEditor extends React.Component<
|
||||
multiline
|
||||
fullWidth
|
||||
disabled={
|
||||
false /* Long description, if shown, can always be changed */
|
||||
/* When parameter are freezed, long description (if shown) can always be changed */
|
||||
isParameterDisabled(i) && !freezeParameters
|
||||
}
|
||||
/>
|
||||
)}
|
||||
@@ -673,6 +468,10 @@ export default class EventsFunctionParametersEditor extends React.Component<
|
||||
label={<Trans>Add a parameter</Trans>}
|
||||
onClick={this._addParameter}
|
||||
icon={<Add />}
|
||||
disabled={
|
||||
eventsFunction.getFunctionType() ===
|
||||
gd.EventsFunction.ActionWithOperator
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Line>
|
||||
|
@@ -8,7 +8,7 @@ import * as React from 'react';
|
||||
import { Column, Line, Spacer } from '../../UI/Grid';
|
||||
import SelectField from '../../UI/SelectField';
|
||||
import SelectOption from '../../UI/SelectOption';
|
||||
import { mapVector } from '../../Utils/MapFor';
|
||||
import { mapVector, mapFor } from '../../Utils/MapFor';
|
||||
import HelpButton from '../../UI/HelpButton';
|
||||
import SemiControlledTextField from '../../UI/SemiControlledTextField';
|
||||
import {
|
||||
@@ -22,13 +22,16 @@ import { type MessageDescriptor } from '../../Utils/i18n/MessageDescriptor.flow'
|
||||
import { ResponsiveLineStackLayout, ColumnStackLayout } from '../../UI/Layout';
|
||||
import DismissableAlertMessage from '../../UI/DismissableAlertMessage';
|
||||
import SemiControlledAutoComplete from '../../UI/SemiControlledAutoComplete';
|
||||
import ValueTypeEditor from './ValueTypeEditor';
|
||||
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
type Props = {|
|
||||
project: gdProject,
|
||||
eventsFunction: gdEventsFunction,
|
||||
eventsBasedBehavior: ?gdEventsBasedBehavior,
|
||||
eventsBasedObject: ?gdEventsBasedObject,
|
||||
eventsFunctionsContainer: ?gdEventsFunctionsContainer,
|
||||
helpPagePath?: string,
|
||||
onConfigurationUpdated?: (whatChanged?: 'type') => void,
|
||||
renderConfigurationHeader?: () => React.Node,
|
||||
@@ -56,11 +59,19 @@ export const getSentenceErrorText = (
|
||||
? ParametersIndexOffsets.ObjectFunction
|
||||
: ParametersIndexOffsets.FreeFunction;
|
||||
|
||||
const type = eventsFunction.getFunctionType();
|
||||
const param0isImplicit =
|
||||
(eventsBasedBehavior || eventsBasedObject) &&
|
||||
type === gd.EventsFunction.ExpressionAndCondition;
|
||||
const missingParameters = mapVector(
|
||||
eventsFunction.getParameters(),
|
||||
(parameter, index) => {
|
||||
if (gd.ParameterMetadata.isBehavior(parameter.getType())) {
|
||||
return null; // Behaviors are usually not shown in sentences.
|
||||
if (parameter.getValueTypeMetadata().isBehavior()) {
|
||||
// Behaviors are usually not shown in sentences.
|
||||
return null;
|
||||
}
|
||||
if (index === 0 && param0isImplicit) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const expectedString = `_PARAM${index + parametersIndexOffset}_`;
|
||||
@@ -103,27 +114,32 @@ export const getSentenceErrorText = (
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const getFullNameHintText = (type: any): MessageDescriptor => {
|
||||
const getFullNameHintText = (
|
||||
type: EventsFunction_FunctionType,
|
||||
expressionType: gdValueTypeMetadata
|
||||
): MessageDescriptor => {
|
||||
if (type === gd.EventsFunction.Condition) {
|
||||
return t`Example: Is flashing`;
|
||||
} else if (type === gd.EventsFunction.Expression) {
|
||||
return t`Example: Remaining life`;
|
||||
} else if (type === gd.EventsFunction.StringExpression) {
|
||||
return t`Example: Equipped shield name`;
|
||||
return expressionType.isNumber()
|
||||
? t`Example: Remaining life`
|
||||
: t`Example: Equipped shield name`;
|
||||
}
|
||||
|
||||
return t`Example: Flash the object`;
|
||||
};
|
||||
|
||||
const getDescriptionHintText = (type: any): MessageDescriptor => {
|
||||
const getDescriptionHintText = (
|
||||
type: EventsFunction_FunctionType,
|
||||
expressionType: gdValueTypeMetadata
|
||||
): MessageDescriptor => {
|
||||
if (type === gd.EventsFunction.Condition) {
|
||||
return t`Example: Check if the object is flashing.`;
|
||||
} else if (type === gd.EventsFunction.Expression) {
|
||||
return t`Example: Return the number of remaining lives for the player.`;
|
||||
} else if (type === gd.EventsFunction.StringExpression) {
|
||||
return t`Example: Return the name of the shield equipped by the player.`;
|
||||
return expressionType.isNumber()
|
||||
? t`Example: Return the number of remaining lives for the player.`
|
||||
: t`Example: Return the name of the shield equipped by the player.`;
|
||||
}
|
||||
|
||||
return t`Example: Make the object flash for 5 seconds.`;
|
||||
};
|
||||
|
||||
@@ -133,6 +149,7 @@ export default class EventsFunctionPropertiesEditor extends React.Component<
|
||||
> {
|
||||
render() {
|
||||
const {
|
||||
project,
|
||||
eventsFunction,
|
||||
freezeEventsFunctionType,
|
||||
onConfigurationUpdated,
|
||||
@@ -141,6 +158,7 @@ export default class EventsFunctionPropertiesEditor extends React.Component<
|
||||
eventsBasedBehavior,
|
||||
eventsBasedObject,
|
||||
getFunctionGroupNames,
|
||||
eventsFunctionsContainer,
|
||||
} = this.props;
|
||||
|
||||
const type = eventsFunction.getFunctionType();
|
||||
@@ -205,6 +223,17 @@ export default class EventsFunctionPropertiesEditor extends React.Component<
|
||||
);
|
||||
}
|
||||
|
||||
const getterFunction =
|
||||
eventsFunctionsContainer &&
|
||||
type === gd.EventsFunction.ActionWithOperator &&
|
||||
eventsFunctionsContainer.hasEventsFunctionNamed(
|
||||
eventsFunction.getGetterName()
|
||||
)
|
||||
? eventsFunctionsContainer.getEventsFunction(
|
||||
eventsFunction.getGetterName()
|
||||
)
|
||||
: null;
|
||||
|
||||
return (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
@@ -217,8 +246,9 @@ export default class EventsFunctionPropertiesEditor extends React.Component<
|
||||
floatingLabelText={<Trans>Function type</Trans>}
|
||||
fullWidth
|
||||
disabled={!!freezeEventsFunctionType}
|
||||
onChange={(e, i, value: string) => {
|
||||
onChange={(e, i, valueString: string) => {
|
||||
// $FlowFixMe
|
||||
const value: EventsFunction_FunctionType = valueString;
|
||||
eventsFunction.setFunctionType(value);
|
||||
if (onConfigurationUpdated) onConfigurationUpdated('type');
|
||||
this.forceUpdate();
|
||||
@@ -237,86 +267,218 @@ export default class EventsFunctionPropertiesEditor extends React.Component<
|
||||
primaryText={t`Expression`}
|
||||
/>
|
||||
<SelectOption
|
||||
value={gd.EventsFunction.StringExpression}
|
||||
primaryText={t`String Expression`}
|
||||
value={gd.EventsFunction.ExpressionAndCondition}
|
||||
primaryText={t`Expression and condition`}
|
||||
/>
|
||||
<SelectOption
|
||||
value={gd.EventsFunction.ActionWithOperator}
|
||||
primaryText={t`Action with operator`}
|
||||
/>
|
||||
</SelectField>
|
||||
</Line>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Full name displayed in editor</Trans>}
|
||||
translatableHintText={getFullNameHintText(type)}
|
||||
value={eventsFunction.getFullName()}
|
||||
onChange={text => {
|
||||
eventsFunction.setFullName(text);
|
||||
if (onConfigurationUpdated) onConfigurationUpdated();
|
||||
this.forceUpdate();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
<Column expand noMargin>
|
||||
{type === gd.EventsFunction.ActionWithOperator ? (
|
||||
<SelectField
|
||||
value={(getterFunction && getterFunction.getName()) || ''}
|
||||
floatingLabelText={
|
||||
<Trans>Related action and expression</Trans>
|
||||
}
|
||||
fullWidth
|
||||
onChange={(e, i, value: string) => {
|
||||
eventsFunction.setGetterName(value);
|
||||
if (onConfigurationUpdated) onConfigurationUpdated();
|
||||
this.forceUpdate();
|
||||
}}
|
||||
>
|
||||
{eventsFunctionsContainer
|
||||
? mapFor(
|
||||
0,
|
||||
eventsFunctionsContainer.getEventsFunctionsCount(),
|
||||
i => {
|
||||
const eventsFunction = eventsFunctionsContainer.getEventsFunctionAt(
|
||||
i
|
||||
);
|
||||
|
||||
return (
|
||||
eventsFunction.getFunctionType() ===
|
||||
gd.EventsFunction.ExpressionAndCondition && (
|
||||
<SelectOption
|
||||
key={eventsFunction.getName()}
|
||||
value={eventsFunction.getName()}
|
||||
primaryText={
|
||||
eventsFunction.getFullName() ||
|
||||
eventsFunction.getName()
|
||||
}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
)
|
||||
: []}
|
||||
</SelectField>
|
||||
) : (
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={
|
||||
<Trans>Full name displayed in editor</Trans>
|
||||
}
|
||||
translatableHintText={getFullNameHintText(
|
||||
type,
|
||||
eventsFunction.getExpressionType()
|
||||
)}
|
||||
value={eventsFunction.getFullName()}
|
||||
onChange={text => {
|
||||
eventsFunction.setFullName(text);
|
||||
if (onConfigurationUpdated) onConfigurationUpdated();
|
||||
this.forceUpdate();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
</Column>
|
||||
<Column expand noMargin>
|
||||
{type === gd.EventsFunction.ActionWithOperator ? (
|
||||
<SemiControlledTextField
|
||||
disabled
|
||||
floatingLabelText={<Trans>Group name</Trans>}
|
||||
fullWidth
|
||||
value={getterFunction ? getterFunction.getGroup() : ''}
|
||||
onChange={text => {}}
|
||||
/>
|
||||
) : (
|
||||
<SemiControlledAutoComplete
|
||||
floatingLabelText={<Trans>Group name</Trans>}
|
||||
hintText={t`Leave it empty to use the default group for this extension.`}
|
||||
fullWidth
|
||||
value={eventsFunction.getGroup()}
|
||||
onChange={text => {
|
||||
eventsFunction.setGroup(text);
|
||||
if (onConfigurationUpdated) onConfigurationUpdated();
|
||||
this.forceUpdate();
|
||||
}}
|
||||
dataSource={
|
||||
getFunctionGroupNames
|
||||
? getFunctionGroupNames().map(name => ({
|
||||
text: name,
|
||||
value: name,
|
||||
}))
|
||||
: []
|
||||
}
|
||||
openOnFocus={true}
|
||||
/>
|
||||
)}
|
||||
</Column>
|
||||
</ResponsiveLineStackLayout>
|
||||
<Line noMargin>
|
||||
<SemiControlledAutoComplete
|
||||
floatingLabelText={<Trans>Group name</Trans>}
|
||||
hintText={t`Leave it empty to use the default group for this extension.`}
|
||||
fullWidth
|
||||
value={eventsFunction.getGroup()}
|
||||
onChange={text => {
|
||||
eventsFunction.setGroup(text);
|
||||
if (onConfigurationUpdated) onConfigurationUpdated();
|
||||
this.forceUpdate();
|
||||
}}
|
||||
dataSource={
|
||||
getFunctionGroupNames
|
||||
? getFunctionGroupNames().map(name => ({
|
||||
text: name,
|
||||
value: name,
|
||||
}))
|
||||
: []
|
||||
}
|
||||
openOnFocus={true}
|
||||
/>
|
||||
</Line>
|
||||
<Line noMargin>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={
|
||||
<Trans>Description, displayed in editor</Trans>
|
||||
}
|
||||
translatableHintText={getDescriptionHintText(type)}
|
||||
fullWidth
|
||||
multiline
|
||||
value={eventsFunction.getDescription()}
|
||||
onChange={text => {
|
||||
eventsFunction.setDescription(text);
|
||||
if (onConfigurationUpdated) onConfigurationUpdated();
|
||||
this.forceUpdate();
|
||||
}}
|
||||
/>
|
||||
</Line>
|
||||
<Line noMargin>
|
||||
{type === gd.EventsFunction.Action ||
|
||||
type === gd.EventsFunction.Condition ? (
|
||||
{type === gd.EventsFunction.ActionWithOperator ? (
|
||||
<SemiControlledTextField
|
||||
disabled
|
||||
commitOnBlur
|
||||
floatingLabelText={
|
||||
<Trans>Description, displayed in editor</Trans>
|
||||
}
|
||||
fullWidth
|
||||
multiline
|
||||
value={
|
||||
getterFunction
|
||||
? 'Change ' + getterFunction.getDescription()
|
||||
: ''
|
||||
}
|
||||
onChange={text => {}}
|
||||
/>
|
||||
) : (
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Sentence in Events Sheet</Trans>}
|
||||
translatableHintText={t`Note: write _PARAMx_ for parameters, e.g: Flash _PARAM1_ for 5 seconds`}
|
||||
floatingLabelText={
|
||||
type === gd.EventsFunction.ExpressionAndCondition ? (
|
||||
<Trans>
|
||||
Description, displayed in editor (automatically prefixed
|
||||
by "Compare" or "Return")
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>Description, displayed in editor</Trans>
|
||||
)
|
||||
}
|
||||
translatableHintText={getDescriptionHintText(
|
||||
type,
|
||||
eventsFunction.getExpressionType()
|
||||
)}
|
||||
fullWidth
|
||||
value={eventsFunction.getSentence()}
|
||||
multiline
|
||||
value={eventsFunction.getDescription()}
|
||||
onChange={text => {
|
||||
eventsFunction.setSentence(text);
|
||||
eventsFunction.setDescription(text);
|
||||
if (onConfigurationUpdated) onConfigurationUpdated();
|
||||
this.forceUpdate();
|
||||
}}
|
||||
errorText={getSentenceErrorText(
|
||||
i18n,
|
||||
eventsBasedBehavior,
|
||||
eventsBasedObject,
|
||||
eventsFunction
|
||||
)}
|
||||
/>
|
||||
) : null}
|
||||
)}
|
||||
</Line>
|
||||
{type === gd.EventsFunction.ActionWithOperator ? (
|
||||
<Line noMargin>
|
||||
<SemiControlledTextField
|
||||
disabled
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Sentence in Events Sheet</Trans>}
|
||||
fullWidth
|
||||
value={
|
||||
getterFunction
|
||||
? 'Change ' +
|
||||
getterFunction.getSentence() +
|
||||
' of _PARAM0_'
|
||||
: ''
|
||||
}
|
||||
onChange={text => {}}
|
||||
/>
|
||||
</Line>
|
||||
) : (
|
||||
(type === gd.EventsFunction.Action ||
|
||||
type === gd.EventsFunction.Condition ||
|
||||
type === gd.EventsFunction.ExpressionAndCondition) && (
|
||||
<Line noMargin>
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={
|
||||
eventsBasedBehavior &&
|
||||
type === gd.EventsFunction.ExpressionAndCondition ? (
|
||||
<Trans>
|
||||
Sentence in Events Sheet (automatically suffixed by
|
||||
"of _PARAM0_")
|
||||
</Trans>
|
||||
) : (
|
||||
<Trans>Sentence in Events Sheet</Trans>
|
||||
)
|
||||
}
|
||||
translatableHintText={t`Note: write _PARAMx_ for parameters, e.g: Flash _PARAM1_ for 5 seconds`}
|
||||
fullWidth
|
||||
value={eventsFunction.getSentence()}
|
||||
onChange={text => {
|
||||
eventsFunction.setSentence(text);
|
||||
if (onConfigurationUpdated) onConfigurationUpdated();
|
||||
this.forceUpdate();
|
||||
}}
|
||||
errorText={getSentenceErrorText(
|
||||
i18n,
|
||||
eventsBasedBehavior,
|
||||
eventsBasedObject,
|
||||
eventsFunction
|
||||
)}
|
||||
/>
|
||||
</Line>
|
||||
)
|
||||
)}
|
||||
{eventsFunction.isExpression() && (
|
||||
<ValueTypeEditor
|
||||
isExpressionType
|
||||
project={project}
|
||||
valueTypeMetadata={eventsFunction.getExpressionType()}
|
||||
isTypeSelectorShown={true}
|
||||
onTypeUpdated={() => {
|
||||
if (onConfigurationUpdated) onConfigurationUpdated();
|
||||
}}
|
||||
getLastObjectParameterObjectType={() => ''}
|
||||
/>
|
||||
)}
|
||||
{helpPagePath ? (
|
||||
<Line noMargin>
|
||||
<HelpButton helpPagePath={helpPagePath} />
|
||||
|
@@ -0,0 +1,244 @@
|
||||
// @flow
|
||||
import { Trans } from '@lingui/macro';
|
||||
import { t } from '@lingui/macro';
|
||||
import { I18n } from '@lingui/react';
|
||||
import * as React from 'react';
|
||||
import SelectField from '../../UI/SelectField';
|
||||
import SelectOption from '../../UI/SelectOption';
|
||||
import SemiControlledTextField from '../../UI/SemiControlledTextField';
|
||||
import ObjectTypeSelector from '../../ObjectTypeSelector';
|
||||
import BehaviorTypeSelector from '../../BehaviorTypeSelector';
|
||||
import { ColumnStackLayout, ResponsiveLineStackLayout } from '../../UI/Layout';
|
||||
import StringArrayEditor from '../../StringArrayEditor';
|
||||
import useForceUpdate from '../../Utils/UseForceUpdate';
|
||||
|
||||
type Props = {|
|
||||
project: gdProject,
|
||||
valueTypeMetadata: gdValueTypeMetadata,
|
||||
onTypeUpdated: () => void,
|
||||
disabled?: boolean,
|
||||
isTypeSelectorShown: boolean,
|
||||
isExpressionType?: boolean,
|
||||
getLastObjectParameterObjectType: () => string,
|
||||
|};
|
||||
|
||||
const getExtraInfoArray = (type: gdValueTypeMetadata) => {
|
||||
const extraInfoJson = type.getExtraInfo();
|
||||
let array = [];
|
||||
try {
|
||||
if (extraInfoJson !== '') array = JSON.parse(extraInfoJson);
|
||||
if (!Array.isArray(array)) array = [];
|
||||
} catch (e) {
|
||||
console.error('Cannot parse parameter extraInfo: ', e);
|
||||
}
|
||||
return array;
|
||||
};
|
||||
|
||||
const getIdentifierScope = (scopedIdentifier: string) =>
|
||||
scopedIdentifier.startsWith('object') ? 'object' : 'scene';
|
||||
|
||||
const getIdentifierName = (scopedIdentifier: string) =>
|
||||
scopedIdentifier.startsWith('object')
|
||||
? scopedIdentifier.substring('object'.length)
|
||||
: scopedIdentifier.substring('scene'.length);
|
||||
|
||||
export default function ValueTypeEditor({
|
||||
project,
|
||||
valueTypeMetadata,
|
||||
disabled,
|
||||
isTypeSelectorShown,
|
||||
onTypeUpdated,
|
||||
getLastObjectParameterObjectType,
|
||||
isExpressionType,
|
||||
}: Props) {
|
||||
const forceUpdate = useForceUpdate();
|
||||
|
||||
return (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<ColumnStackLayout noMargin expand>
|
||||
<ResponsiveLineStackLayout noMargin>
|
||||
{isTypeSelectorShown && (
|
||||
<SelectField
|
||||
floatingLabelText={<Trans>Type</Trans>}
|
||||
value={valueTypeMetadata.getName()}
|
||||
onChange={(e, i, value: string) => {
|
||||
valueTypeMetadata.setName(value);
|
||||
valueTypeMetadata.setOptional(false);
|
||||
valueTypeMetadata.setDefaultValue('');
|
||||
forceUpdate();
|
||||
onTypeUpdated();
|
||||
}}
|
||||
disabled={disabled}
|
||||
fullWidth
|
||||
>
|
||||
{!isExpressionType && (
|
||||
<SelectOption value="objectList" primaryText={t`Objects`} />
|
||||
)}
|
||||
{!isExpressionType && (
|
||||
<SelectOption
|
||||
value="behavior"
|
||||
primaryText={t`Behavior (for the previous object)`}
|
||||
/>
|
||||
)}
|
||||
<SelectOption value="expression" primaryText={t`Number`} />
|
||||
<SelectOption value="string" primaryText={t`String (text)`} />
|
||||
<SelectOption
|
||||
value="stringWithSelector"
|
||||
primaryText={t`String from a list of options (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="key"
|
||||
primaryText={t`Keyboard Key (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="mouse"
|
||||
primaryText={t`Mouse button (text)`}
|
||||
/>
|
||||
<SelectOption value="color" primaryText={t`Color (text)`} />
|
||||
<SelectOption value="layer" primaryText={t`Layer (text)`} />
|
||||
<SelectOption
|
||||
value="sceneName"
|
||||
primaryText={t`Scene name (text)`}
|
||||
/>
|
||||
{!isExpressionType && (
|
||||
<SelectOption
|
||||
value="yesorno"
|
||||
primaryText={t`Yes or No (boolean)`}
|
||||
/>
|
||||
)}
|
||||
{!isExpressionType && (
|
||||
<SelectOption
|
||||
value="trueorfalse"
|
||||
primaryText={t`True or False (boolean)`}
|
||||
/>
|
||||
)}
|
||||
<SelectOption
|
||||
value="objectPointName"
|
||||
primaryText={t`Object point (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="objectAnimationName"
|
||||
primaryText={t`Object animation (text)`}
|
||||
/>
|
||||
<SelectOption
|
||||
value="identifier"
|
||||
primaryText={t`Identifier (text)`}
|
||||
/>
|
||||
</SelectField>
|
||||
)}
|
||||
{valueTypeMetadata.isObject() && (
|
||||
<ObjectTypeSelector
|
||||
project={project}
|
||||
value={valueTypeMetadata.getExtraInfo()}
|
||||
onChange={(value: string) => {
|
||||
valueTypeMetadata.setExtraInfo(value);
|
||||
forceUpdate();
|
||||
onTypeUpdated();
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
{valueTypeMetadata.isBehavior() && (
|
||||
<BehaviorTypeSelector
|
||||
project={project}
|
||||
objectType={getLastObjectParameterObjectType()}
|
||||
value={valueTypeMetadata.getExtraInfo()}
|
||||
onChange={(value: string) => {
|
||||
valueTypeMetadata.setExtraInfo(value);
|
||||
forceUpdate();
|
||||
onTypeUpdated();
|
||||
}}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
{valueTypeMetadata.getName() === 'yesorno' && (
|
||||
<SelectField
|
||||
floatingLabelText={<Trans>Default value</Trans>}
|
||||
value={
|
||||
valueTypeMetadata.getDefaultValue() === 'yes' ? 'yes' : 'no'
|
||||
}
|
||||
onChange={(e, i, value) => {
|
||||
valueTypeMetadata.setOptional(true);
|
||||
valueTypeMetadata.setDefaultValue(value);
|
||||
forceUpdate();
|
||||
onTypeUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<SelectOption value="yes" primaryText={t`Yes`} />
|
||||
<SelectOption value="no" primaryText={t`No`} />
|
||||
</SelectField>
|
||||
)}
|
||||
{valueTypeMetadata.getName() === 'trueorfalse' && (
|
||||
<SelectField
|
||||
floatingLabelText={<Trans>Default value</Trans>}
|
||||
value={
|
||||
valueTypeMetadata.getDefaultValue() === 'True'
|
||||
? 'True'
|
||||
: 'False'
|
||||
}
|
||||
onChange={(e, i, value) => {
|
||||
valueTypeMetadata.setOptional(true);
|
||||
valueTypeMetadata.setDefaultValue(value);
|
||||
forceUpdate();
|
||||
onTypeUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<SelectOption value="True" primaryText={t`True`} />
|
||||
<SelectOption value="False" primaryText={t`False`} />
|
||||
</SelectField>
|
||||
)}
|
||||
{valueTypeMetadata.getName() === 'identifier' && (
|
||||
<SelectField
|
||||
floatingLabelText={<Trans>Scope</Trans>}
|
||||
value={getIdentifierScope(valueTypeMetadata.getExtraInfo())}
|
||||
onChange={(e, i, value) => {
|
||||
const identifierName = getIdentifierName(
|
||||
valueTypeMetadata.getExtraInfo()
|
||||
);
|
||||
valueTypeMetadata.setExtraInfo(value + identifierName);
|
||||
forceUpdate();
|
||||
onTypeUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
>
|
||||
<SelectOption value="scene" primaryText={t`Scene`} />
|
||||
<SelectOption value="object" primaryText={t`Object`} />
|
||||
</SelectField>
|
||||
)}
|
||||
{valueTypeMetadata.getName() === 'identifier' && (
|
||||
<SemiControlledTextField
|
||||
commitOnBlur
|
||||
floatingLabelText={<Trans>Identifier name</Trans>}
|
||||
floatingLabelFixed
|
||||
value={getIdentifierName(valueTypeMetadata.getExtraInfo())}
|
||||
onChange={value => {
|
||||
const scope = getIdentifierScope(
|
||||
valueTypeMetadata.getExtraInfo()
|
||||
);
|
||||
valueTypeMetadata.setExtraInfo(scope + value);
|
||||
forceUpdate();
|
||||
onTypeUpdated();
|
||||
}}
|
||||
fullWidth
|
||||
/>
|
||||
)}
|
||||
</ResponsiveLineStackLayout>
|
||||
{valueTypeMetadata.getName() === 'stringWithSelector' && (
|
||||
<StringArrayEditor
|
||||
disabled={disabled}
|
||||
extraInfo={getExtraInfoArray(valueTypeMetadata)}
|
||||
setExtraInfo={(newExtraInfo: Array<string>) => {
|
||||
valueTypeMetadata.setExtraInfo(JSON.stringify(newExtraInfo));
|
||||
forceUpdate();
|
||||
onTypeUpdated();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ColumnStackLayout>
|
||||
)}
|
||||
</I18n>
|
||||
);
|
||||
}
|
@@ -22,6 +22,7 @@ type Props = {|
|
||||
eventsFunction: gdEventsFunction,
|
||||
eventsBasedBehavior: ?gdEventsBasedBehavior,
|
||||
eventsBasedObject: ?gdEventsBasedObject,
|
||||
eventsFunctionsContainer: gdEventsFunctionsContainer,
|
||||
onParametersOrGroupsUpdated: () => void,
|
||||
helpPagePath?: string,
|
||||
onConfigurationUpdated?: (whatChanged?: 'type') => void,
|
||||
@@ -173,6 +174,7 @@ export default class EventsFunctionConfigurationEditor extends React.Component<
|
||||
onMoveBehaviorEventsParameter,
|
||||
onMoveObjectEventsParameter,
|
||||
getFunctionGroupNames,
|
||||
eventsFunctionsContainer,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@@ -195,9 +197,11 @@ export default class EventsFunctionConfigurationEditor extends React.Component<
|
||||
<ScrollView>
|
||||
<Line>
|
||||
<EventsFunctionPropertiesEditor
|
||||
project={project}
|
||||
eventsFunction={eventsFunction}
|
||||
eventsBasedBehavior={eventsBasedBehavior}
|
||||
eventsBasedObject={eventsBasedObject}
|
||||
eventsFunctionsContainer={eventsFunctionsContainer}
|
||||
helpPagePath={helpPagePath}
|
||||
onConfigurationUpdated={onConfigurationUpdated}
|
||||
renderConfigurationHeader={renderConfigurationHeader}
|
||||
@@ -215,6 +219,7 @@ export default class EventsFunctionConfigurationEditor extends React.Component<
|
||||
eventsFunction={eventsFunction}
|
||||
eventsBasedBehavior={eventsBasedBehavior}
|
||||
eventsBasedObject={eventsBasedObject}
|
||||
eventsFunctionsContainer={eventsFunctionsContainer}
|
||||
onParametersUpdated={onParametersOrGroupsUpdated}
|
||||
helpPagePath={helpPagePath}
|
||||
freezeParameters={freezeParameters}
|
||||
|
@@ -169,7 +169,8 @@ export default class EventsFunctionsExtensionEditor extends React.Component<
|
||||
project: gdProject,
|
||||
eventsFunction: gdEventsFunction,
|
||||
eventsBasedBehavior: ?gdEventsBasedBehavior,
|
||||
eventsBasedObject: ?gdEventsBasedObject
|
||||
eventsBasedObject: ?gdEventsBasedObject,
|
||||
eventsFunctionsExtension: ?gdEventsFunctionsExtension
|
||||
) => {
|
||||
// Initialize this "context" of objects with the function
|
||||
// (as done during code generation).
|
||||
@@ -189,13 +190,18 @@ export default class EventsFunctionsExtensionEditor extends React.Component<
|
||||
this._globalObjectsContainer,
|
||||
this._objectsContainer
|
||||
);
|
||||
} else {
|
||||
} else if (eventsFunctionsExtension) {
|
||||
gd.EventsFunctionTools.freeEventsFunctionToObjectsContainer(
|
||||
project,
|
||||
eventsFunctionsExtension,
|
||||
eventsFunction,
|
||||
this._globalObjectsContainer,
|
||||
this._objectsContainer
|
||||
);
|
||||
} else {
|
||||
throw new Error(
|
||||
'No extension, behavior or object was specified when loading a function'
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -258,7 +264,8 @@ export default class EventsFunctionsExtensionEditor extends React.Component<
|
||||
this.props.project,
|
||||
selectedEventsFunction,
|
||||
selectedEventsBasedBehavior,
|
||||
selectedEventsBasedObject
|
||||
selectedEventsBasedObject,
|
||||
this.props.eventsFunctionsExtension
|
||||
);
|
||||
this.setState(
|
||||
{
|
||||
@@ -592,7 +599,9 @@ export default class EventsFunctionsExtensionEditor extends React.Component<
|
||||
this._loadEventsFunctionFrom(
|
||||
this.props.project,
|
||||
this.state.selectedEventsFunction,
|
||||
this.state.selectedEventsBasedBehavior
|
||||
this.state.selectedEventsBasedBehavior,
|
||||
this.state.selectedEventsBasedObject,
|
||||
this.props.eventsFunctionsExtension
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -611,7 +620,8 @@ export default class EventsFunctionsExtensionEditor extends React.Component<
|
||||
this.props.project,
|
||||
this.state.selectedEventsFunction,
|
||||
this.state.selectedEventsBasedBehavior,
|
||||
this.state.selectedEventsBasedObject
|
||||
this.state.selectedEventsBasedObject,
|
||||
this.props.eventsFunctionsExtension
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -825,7 +835,8 @@ export default class EventsFunctionsExtensionEditor extends React.Component<
|
||||
this.props.project,
|
||||
this.state.selectedEventsFunction,
|
||||
this.state.selectedEventsBasedBehavior,
|
||||
this.state.selectedEventsBasedObject
|
||||
this.state.selectedEventsBasedObject,
|
||||
this.props.eventsFunctionsExtension
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -867,7 +878,8 @@ export default class EventsFunctionsExtensionEditor extends React.Component<
|
||||
this.props.project,
|
||||
this.state.selectedEventsFunction,
|
||||
this.state.selectedEventsBasedBehavior,
|
||||
this.state.selectedEventsBasedObject
|
||||
this.state.selectedEventsBasedObject,
|
||||
this.props.eventsFunctionsExtension
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1000,6 +1012,9 @@ export default class EventsFunctionsExtensionEditor extends React.Component<
|
||||
editedEventsBasedObject,
|
||||
} = this.state;
|
||||
|
||||
const selectedEventsBasedEntity =
|
||||
selectedEventsBasedBehavior || selectedEventsBasedObject;
|
||||
|
||||
const editors = {
|
||||
'choose-editor': {
|
||||
type: 'primary',
|
||||
@@ -1029,6 +1044,11 @@ export default class EventsFunctionsExtensionEditor extends React.Component<
|
||||
eventsFunction={selectedEventsFunction}
|
||||
eventsBasedBehavior={selectedEventsBasedBehavior}
|
||||
eventsBasedObject={selectedEventsBasedObject}
|
||||
eventsFunctionsContainer={
|
||||
(selectedEventsBasedEntity &&
|
||||
selectedEventsBasedEntity.getEventsFunctions()) ||
|
||||
eventsFunctionsExtension
|
||||
}
|
||||
globalObjectsContainer={this._globalObjectsContainer}
|
||||
objectsContainer={this._objectsContainer}
|
||||
onConfigurationUpdated={this._onConfigurationUpdated}
|
||||
@@ -1045,7 +1065,8 @@ export default class EventsFunctionsExtensionEditor extends React.Component<
|
||||
project,
|
||||
selectedEventsFunction,
|
||||
selectedEventsBasedBehavior,
|
||||
selectedEventsBasedObject
|
||||
selectedEventsBasedObject,
|
||||
this.props.eventsFunctionsExtension
|
||||
);
|
||||
this.forceUpdate();
|
||||
}}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
import { type I18n as I18nType } from '@lingui/core';
|
||||
import { t } from '@lingui/macro';
|
||||
import { mapVector } from '../Utils/MapFor';
|
||||
import { getFreeFunctionCodeName } from '.';
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
// This file contains the logic to declare extension metadata from
|
||||
@@ -301,6 +302,12 @@ export const isExtensionLifecycleEventsFunction = (functionName: string) => {
|
||||
);
|
||||
};
|
||||
|
||||
const removeTrailingDot = (description: string): string => {
|
||||
return description.endsWith('.')
|
||||
? description.slice(0, description.length - 1)
|
||||
: description;
|
||||
};
|
||||
|
||||
/**
|
||||
* Declare the instruction (action/condition) or expression for the given
|
||||
* (free) events function.
|
||||
@@ -309,24 +316,80 @@ export const declareInstructionOrExpressionMetadata = (
|
||||
extension: gdPlatformExtension,
|
||||
eventsFunctionsExtension: gdEventsFunctionsExtension,
|
||||
eventsFunction: gdEventsFunction
|
||||
): gdInstructionMetadata | gdExpressionMetadata => {
|
||||
):
|
||||
| gdInstructionMetadata
|
||||
| gdExpressionMetadata
|
||||
| gdMultipleInstructionMetadata => {
|
||||
const functionType = eventsFunction.getFunctionType();
|
||||
if (functionType === gd.EventsFunction.Expression) {
|
||||
return extension.addExpression(
|
||||
if (eventsFunction.getExpressionType().isNumber()) {
|
||||
return extension.addExpression(
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
eventsFunction.getGroup() || '',
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
} else {
|
||||
return extension.addStrExpression(
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
eventsFunction.getGroup() || '',
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
}
|
||||
} else if (functionType === gd.EventsFunction.ExpressionAndCondition) {
|
||||
return extension.addExpressionAndCondition(
|
||||
gd.ValueTypeMetadata.getPrimitiveValueType(
|
||||
eventsFunction.getExpressionType().getName()
|
||||
),
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
removeTrailingDot(eventsFunction.getDescription()) ||
|
||||
eventsFunction.getFullName(),
|
||||
// An operator and an operand are inserted before user parameters.
|
||||
shiftSentenceParamIndexes(eventsFunction.getSentence(), 2),
|
||||
eventsFunction.getGroup() || '',
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
} else if (functionType === gd.EventsFunction.StringExpression) {
|
||||
return extension.addStrExpression(
|
||||
} else if (functionType === gd.EventsFunction.ActionWithOperator) {
|
||||
const getterFunction = eventsFunctionsExtension.hasEventsFunctionNamed(
|
||||
eventsFunction.getGetterName()
|
||||
)
|
||||
? eventsFunctionsExtension.getEventsFunction(
|
||||
eventsFunction.getGetterName()
|
||||
)
|
||||
: null;
|
||||
const action = extension.addAction(
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
eventsFunction.getGroup() || '',
|
||||
(getterFunction && getterFunction.getFullName()) ||
|
||||
eventsFunction.getName(),
|
||||
'Change ' +
|
||||
((getterFunction && getterFunction.getDescription()) ||
|
||||
eventsFunction.getFullName()),
|
||||
// An operator and an operand are inserted before user parameters.
|
||||
getterFunction
|
||||
? shiftSentenceParamIndexes(getterFunction.getSentence(), 2)
|
||||
: '',
|
||||
(getterFunction && getterFunction.getGroup()) || '',
|
||||
getExtensionIconUrl(extension),
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
if (getterFunction) {
|
||||
action
|
||||
.getCodeExtraInformation()
|
||||
.setManipulatedType(
|
||||
gd.ValueTypeMetadata.getPrimitiveValueType(
|
||||
getterFunction.getExpressionType().getName()
|
||||
)
|
||||
)
|
||||
// TODO Use an helper method
|
||||
.setGetter(
|
||||
getFreeFunctionCodeName(eventsFunctionsExtension, getterFunction)
|
||||
);
|
||||
}
|
||||
return action;
|
||||
} else if (functionType === gd.EventsFunction.Condition) {
|
||||
return extension.addCondition(
|
||||
eventsFunction.getName(),
|
||||
@@ -350,6 +413,34 @@ export const declareInstructionOrExpressionMetadata = (
|
||||
}
|
||||
};
|
||||
|
||||
export const shiftSentenceParamIndexes = (
|
||||
sentence: string,
|
||||
offset: number
|
||||
): string => {
|
||||
const parameterIndexesStrings = sentence.match(/(?<=_PARAM)(\d+)(?=_)/g);
|
||||
if (!parameterIndexesStrings) {
|
||||
return sentence;
|
||||
}
|
||||
const parameterIndexes = parameterIndexesStrings.map(indexString =>
|
||||
Number.parseInt(indexString)
|
||||
);
|
||||
const sentenceElements = sentence.split(/_PARAM\d+_/);
|
||||
let shiftedSentence = '';
|
||||
for (let index = 0; index < parameterIndexes.length; index++) {
|
||||
shiftedSentence +=
|
||||
sentenceElements[index] +
|
||||
'_PARAM' +
|
||||
(parameterIndexes[index] + offset) +
|
||||
'_';
|
||||
}
|
||||
const sentenceIsEndingWithAnElement =
|
||||
sentenceElements.length > parameterIndexes.length;
|
||||
if (sentenceIsEndingWithAnElement) {
|
||||
shiftedSentence += sentenceElements[sentenceElements.length - 1];
|
||||
}
|
||||
return shiftedSentence;
|
||||
};
|
||||
|
||||
/**
|
||||
* Declare the instruction (action/condition) or expression for the given
|
||||
* behavior events function.
|
||||
@@ -359,28 +450,84 @@ export const declareBehaviorInstructionOrExpressionMetadata = (
|
||||
behaviorMetadata: gdBehaviorMetadata,
|
||||
eventsBasedBehavior: gdEventsBasedBehavior,
|
||||
eventsFunction: gdEventsFunction
|
||||
): gdInstructionMetadata | gdExpressionMetadata => {
|
||||
):
|
||||
| gdInstructionMetadata
|
||||
| gdExpressionMetadata
|
||||
| gdMultipleInstructionMetadata => {
|
||||
const functionType = eventsFunction.getFunctionType();
|
||||
if (functionType === gd.EventsFunction.Expression) {
|
||||
return behaviorMetadata.addExpression(
|
||||
if (eventsFunction.getExpressionType().isNumber()) {
|
||||
return behaviorMetadata.addExpression(
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
eventsFunction.getGroup() ||
|
||||
eventsBasedBehavior.getFullName() ||
|
||||
eventsBasedBehavior.getName(),
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
} else {
|
||||
return behaviorMetadata.addStrExpression(
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
eventsFunction.getGroup() ||
|
||||
eventsBasedBehavior.getFullName() ||
|
||||
eventsBasedBehavior.getName(),
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
}
|
||||
} else if (functionType === gd.EventsFunction.ExpressionAndCondition) {
|
||||
return behaviorMetadata.addExpressionAndCondition(
|
||||
gd.ValueTypeMetadata.getPrimitiveValueType(
|
||||
eventsFunction.getExpressionType().getName()
|
||||
),
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
eventsFunction.getGroup() ||
|
||||
eventsBasedBehavior.getFullName() ||
|
||||
eventsBasedBehavior.getName(),
|
||||
removeTrailingDot(eventsFunction.getDescription()) ||
|
||||
eventsFunction.getFullName(),
|
||||
// An operator and an operand are inserted before user parameters.
|
||||
shiftSentenceParamIndexes(eventsFunction.getSentence(), 2),
|
||||
eventsFunction.getGroup() || '',
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
} else if (functionType === gd.EventsFunction.StringExpression) {
|
||||
return behaviorMetadata.addStrExpression(
|
||||
} else if (functionType === gd.EventsFunction.ActionWithOperator) {
|
||||
const eventsFunctionsContainer = eventsBasedBehavior.getEventsFunctions();
|
||||
const getterFunction = eventsFunctionsContainer.hasEventsFunctionNamed(
|
||||
eventsFunction.getGetterName()
|
||||
)
|
||||
? eventsFunctionsContainer.getEventsFunction(
|
||||
eventsFunction.getGetterName()
|
||||
)
|
||||
: null;
|
||||
const action = behaviorMetadata.addScopedAction(
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
eventsFunction.getGroup() ||
|
||||
(getterFunction && getterFunction.getFullName()) ||
|
||||
eventsFunction.getName(),
|
||||
'Change ' +
|
||||
((getterFunction && getterFunction.getDescription()) ||
|
||||
eventsFunction.getFullName()),
|
||||
// An operator and an operand are inserted before user parameters.
|
||||
getterFunction
|
||||
? shiftSentenceParamIndexes(getterFunction.getSentence(), 2)
|
||||
: '',
|
||||
(getterFunction && getterFunction.getGroup()) ||
|
||||
eventsBasedBehavior.getFullName() ||
|
||||
eventsBasedBehavior.getName(),
|
||||
getExtensionIconUrl(extension),
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
if (getterFunction) {
|
||||
action
|
||||
.getCodeExtraInformation()
|
||||
.setManipulatedType(
|
||||
gd.ValueTypeMetadata.getPrimitiveValueType(
|
||||
getterFunction.getExpressionType().getName()
|
||||
)
|
||||
)
|
||||
.setGetter(getterFunction.getName());
|
||||
}
|
||||
return action;
|
||||
} else if (functionType === gd.EventsFunction.Condition) {
|
||||
// Use the new "scoped" way to declare an instruction, because
|
||||
// we want to prevent any conflict between free functions and
|
||||
@@ -423,28 +570,84 @@ export const declareObjectInstructionOrExpressionMetadata = (
|
||||
objectMetadata: gdObjectMetadata,
|
||||
eventsBasedObject: gdEventsBasedObject,
|
||||
eventsFunction: gdEventsFunction
|
||||
): gdInstructionMetadata | gdExpressionMetadata => {
|
||||
):
|
||||
| gdInstructionMetadata
|
||||
| gdExpressionMetadata
|
||||
| gdMultipleInstructionMetadata => {
|
||||
const functionType = eventsFunction.getFunctionType();
|
||||
if (functionType === gd.EventsFunction.Expression) {
|
||||
return objectMetadata.addExpression(
|
||||
if (eventsFunction.getExpressionType().isNumber()) {
|
||||
return objectMetadata.addExpression(
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
eventsFunction.getGroup() ||
|
||||
eventsBasedObject.getFullName() ||
|
||||
eventsBasedObject.getName(),
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
} else {
|
||||
return objectMetadata.addStrExpression(
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
eventsFunction.getGroup() ||
|
||||
eventsBasedObject.getFullName() ||
|
||||
eventsBasedObject.getName(),
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
}
|
||||
} else if (functionType === gd.EventsFunction.ExpressionAndCondition) {
|
||||
return objectMetadata.addExpressionAndCondition(
|
||||
gd.ValueTypeMetadata.getPrimitiveValueType(
|
||||
eventsFunction.getExpressionType().getName()
|
||||
),
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
eventsFunction.getGroup() ||
|
||||
eventsBasedObject.getFullName() ||
|
||||
eventsBasedObject.getName(),
|
||||
removeTrailingDot(eventsFunction.getDescription()) ||
|
||||
eventsFunction.getFullName(),
|
||||
// An operator and an operand are inserted before user parameters.
|
||||
shiftSentenceParamIndexes(eventsFunction.getSentence(), 2),
|
||||
eventsFunction.getGroup() || '',
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
} else if (functionType === gd.EventsFunction.StringExpression) {
|
||||
return objectMetadata.addStrExpression(
|
||||
} else if (functionType === gd.EventsFunction.ActionWithOperator) {
|
||||
const eventsFunctionsContainer = eventsBasedObject.getEventsFunctions();
|
||||
const getterFunction = eventsFunctionsContainer.hasEventsFunctionNamed(
|
||||
eventsFunction.getGetterName()
|
||||
)
|
||||
? eventsFunctionsContainer.getEventsFunction(
|
||||
eventsFunction.getGetterName()
|
||||
)
|
||||
: null;
|
||||
const action = objectMetadata.addScopedAction(
|
||||
eventsFunction.getName(),
|
||||
eventsFunction.getFullName() || eventsFunction.getName(),
|
||||
eventsFunction.getDescription() || eventsFunction.getFullName(),
|
||||
eventsFunction.getGroup() ||
|
||||
(getterFunction && getterFunction.getFullName()) ||
|
||||
eventsFunction.getName(),
|
||||
'Change ' +
|
||||
((getterFunction && getterFunction.getDescription()) ||
|
||||
eventsFunction.getFullName()),
|
||||
// An operator and an operand are inserted before user parameters.
|
||||
getterFunction
|
||||
? shiftSentenceParamIndexes(getterFunction.getSentence(), 2)
|
||||
: '',
|
||||
(getterFunction && getterFunction.getGroup()) ||
|
||||
eventsBasedObject.getFullName() ||
|
||||
eventsBasedObject.getName(),
|
||||
getExtensionIconUrl(extension),
|
||||
getExtensionIconUrl(extension)
|
||||
);
|
||||
if (getterFunction) {
|
||||
action
|
||||
.getCodeExtraInformation()
|
||||
.setManipulatedType(
|
||||
gd.ValueTypeMetadata.getPrimitiveValueType(
|
||||
getterFunction.getExpressionType().getName()
|
||||
)
|
||||
)
|
||||
.setGetter(getterFunction.getName());
|
||||
}
|
||||
return action;
|
||||
} else if (functionType === gd.EventsFunction.Condition) {
|
||||
// Use the new "scoped" way to declare an instruction, because
|
||||
// we want to prevent any conflict between free functions and
|
||||
@@ -498,19 +701,17 @@ export const declareBehaviorPropertiesInstructionAndExpressions = (
|
||||
instructionOrExpression: T
|
||||
): T => {
|
||||
// By convention, first parameter is always the object:
|
||||
instructionOrExpression.addParameter(
|
||||
'object',
|
||||
'Object',
|
||||
'', // See below for adding the extra information
|
||||
false
|
||||
);
|
||||
|
||||
// Manually add the "extra info" without relying on addParameter
|
||||
// as this method is prefixing the value passed with the extension namespace (this
|
||||
// was done to ease extension declarations when dealing with object).
|
||||
instructionOrExpression
|
||||
.getParameter(instructionOrExpression.getParametersCount() - 1)
|
||||
.setExtraInfo(eventsBasedBehavior.getObjectType());
|
||||
.addParameter(
|
||||
'object',
|
||||
'Object',
|
||||
'', // See below for adding the extra information
|
||||
false
|
||||
)
|
||||
// Manually add the "extra info" without relying on addParameter
|
||||
// as this method is prefixing the value passed with the extension namespace (this
|
||||
// was done to ease extension declarations when dealing with object).
|
||||
.setParameterExtraInfo(eventsBasedBehavior.getObjectType());
|
||||
|
||||
// By convention, second parameter is always the behavior:
|
||||
instructionOrExpression.addParameter(
|
||||
@@ -912,36 +1113,75 @@ export const declareObjectPropertiesInstructionAndExpressions = (
|
||||
* expected by the events function.
|
||||
*/
|
||||
export const declareEventsFunctionParameters = (
|
||||
eventsFunctionsContainer: gdEventsFunctionsContainer,
|
||||
eventsFunction: gdEventsFunction,
|
||||
instructionOrExpression: gdInstructionMetadata | gdExpressionMetadata
|
||||
instructionOrExpression:
|
||||
| gdInstructionMetadata
|
||||
| gdExpressionMetadata
|
||||
| gdMultipleInstructionMetadata,
|
||||
userDefinedFirstParameterIndex: number
|
||||
) => {
|
||||
mapVector(
|
||||
eventsFunction.getParameters(),
|
||||
(parameter: gdParameterMetadata) => {
|
||||
if (!parameter.isCodeOnly()) {
|
||||
instructionOrExpression.addParameter(
|
||||
const addParameter = (parameter: gdParameterMetadata) => {
|
||||
if (!parameter.isCodeOnly()) {
|
||||
instructionOrExpression
|
||||
.addParameter(
|
||||
parameter.getType(),
|
||||
parameter.getDescription(),
|
||||
'', // See below for adding the extra information
|
||||
parameter.isOptional()
|
||||
);
|
||||
instructionOrExpression.setParameterLongDescription(
|
||||
parameter.getLongDescription()
|
||||
);
|
||||
instructionOrExpression.setDefaultValue(parameter.getDefaultValue());
|
||||
} else {
|
||||
instructionOrExpression.addCodeOnlyParameter(
|
||||
parameter.getType(),
|
||||
'' // See below for adding the extra information
|
||||
);
|
||||
}
|
||||
// Manually add the "extra info" without relying on addParameter (or addCodeOnlyParameter)
|
||||
// as these methods are prefixing the value passed with the extension namespace (this
|
||||
// was done to ease extension declarations when dealing with object).
|
||||
instructionOrExpression
|
||||
.getParameter(instructionOrExpression.getParametersCount() - 1)
|
||||
.setExtraInfo(parameter.getExtraInfo());
|
||||
)
|
||||
// Manually add the "extra info" without relying on addParameter (or addCodeOnlyParameter)
|
||||
// as these methods are prefixing the value passed with the extension namespace (this
|
||||
// was done to ease extension declarations when dealing with object).
|
||||
.setParameterExtraInfo(parameter.getExtraInfo());
|
||||
instructionOrExpression.setParameterLongDescription(
|
||||
parameter.getLongDescription()
|
||||
);
|
||||
instructionOrExpression.setDefaultValue(parameter.getDefaultValue());
|
||||
} else {
|
||||
instructionOrExpression.addCodeOnlyParameter(
|
||||
parameter.getType(),
|
||||
parameter.getExtraInfo()
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const functionType = eventsFunction.getFunctionType();
|
||||
const getterFunction = eventsFunctionsContainer.hasEventsFunctionNamed(
|
||||
eventsFunction.getGetterName()
|
||||
)
|
||||
? eventsFunctionsContainer.getEventsFunction(eventsFunction.getGetterName())
|
||||
: null;
|
||||
// This is used instead of getParametersForEvents because the Value parameter
|
||||
// is already add by useStandardOperatorParameters.
|
||||
const parameters = (functionType === gd.EventsFunction.ActionWithOperator &&
|
||||
getterFunction
|
||||
? getterFunction
|
||||
: eventsFunction
|
||||
).getParameters();
|
||||
|
||||
mapVector(
|
||||
parameters,
|
||||
(parameter: gdParameterMetadata, index: number) =>
|
||||
index < userDefinedFirstParameterIndex && addParameter(parameter)
|
||||
);
|
||||
|
||||
if (functionType === gd.EventsFunction.ExpressionAndCondition) {
|
||||
((instructionOrExpression: any): gdMultipleInstructionMetadata).useStandardParameters(
|
||||
eventsFunction ? eventsFunction.getExpressionType().getName() : 'string',
|
||||
eventsFunction ? eventsFunction.getExpressionType().getExtraInfo() : ''
|
||||
);
|
||||
} else if (functionType === gd.EventsFunction.ActionWithOperator) {
|
||||
((instructionOrExpression: any): gdInstructionMetadata).useStandardOperatorParameters(
|
||||
getterFunction ? getterFunction.getExpressionType().getName() : 'string',
|
||||
getterFunction ? getterFunction.getExpressionType().getExtraInfo() : ''
|
||||
);
|
||||
}
|
||||
|
||||
mapVector(
|
||||
parameters,
|
||||
(parameter: gdParameterMetadata, index: number) =>
|
||||
index >= userDefinedFirstParameterIndex && addParameter(parameter)
|
||||
);
|
||||
|
||||
// By convention, latest parameter is always the eventsFunctionContext of the calling function
|
||||
|
@@ -0,0 +1,91 @@
|
||||
// @flow
|
||||
import { shiftSentenceParamIndexes } from './MetadataDeclarationHelpers';
|
||||
|
||||
describe('shiftSentenceParamIndexes', () => {
|
||||
it('give back the sentence when there is no parameters', () => {
|
||||
expect(shiftSentenceParamIndexes('Make an action', 2)).toBe(
|
||||
'Make an action'
|
||||
);
|
||||
});
|
||||
it('can shift a parameter at the end', () => {
|
||||
expect(shiftSentenceParamIndexes('Change the speed to _PARAM2_', 2)).toBe(
|
||||
'Change the speed to _PARAM4_'
|
||||
);
|
||||
});
|
||||
it('can shift a parameter at the beginning', () => {
|
||||
expect(shiftSentenceParamIndexes('_PARAM2_ is moving', 2)).toBe(
|
||||
'_PARAM4_ is moving'
|
||||
);
|
||||
});
|
||||
it('can shift a parameter alone', () => {
|
||||
expect(shiftSentenceParamIndexes('_PARAM2_', 2)).toBe('_PARAM4_');
|
||||
});
|
||||
it("won't shift an ill-formed parameter", () => {
|
||||
expect(
|
||||
shiftSentenceParamIndexes(
|
||||
'The speed is greater than PARAM2_ pixels per second',
|
||||
2
|
||||
)
|
||||
).toBe('The speed is greater than PARAM2_ pixels per second');
|
||||
expect(
|
||||
shiftSentenceParamIndexes(
|
||||
'The speed is greater than _PARAM2 pixels per second',
|
||||
2
|
||||
)
|
||||
).toBe('The speed is greater than _PARAM2 pixels per second');
|
||||
expect(
|
||||
shiftSentenceParamIndexes(
|
||||
'The speed is greater than PARAM2 pixels per second',
|
||||
2
|
||||
)
|
||||
).toBe('The speed is greater than PARAM2 pixels per second');
|
||||
expect(
|
||||
shiftSentenceParamIndexes(
|
||||
'The speed is greater than _param2_ pixels per second',
|
||||
2
|
||||
)
|
||||
).toBe('The speed is greater than _param2_ pixels per second');
|
||||
expect(
|
||||
shiftSentenceParamIndexes(
|
||||
'The speed is greater than 2 pixels per second',
|
||||
2
|
||||
)
|
||||
).toBe('The speed is greater than 2 pixels per second');
|
||||
});
|
||||
[2, 0, -2].forEach(indexOffset => {
|
||||
it(`can shift 1 parameter by ${indexOffset}`, () => {
|
||||
expect(
|
||||
shiftSentenceParamIndexes(
|
||||
'The speed is greater than _PARAM2_ pixels per second',
|
||||
indexOffset
|
||||
)
|
||||
).toBe(
|
||||
'The speed is greater than _PARAM' +
|
||||
(2 + indexOffset) +
|
||||
'_ pixels per second'
|
||||
);
|
||||
});
|
||||
it(`can shift 2 parameters by ${indexOffset}`, () => {
|
||||
expect(
|
||||
shiftSentenceParamIndexes(
|
||||
'The speed is between _PARAM1_ and _PARAM2_ pixels per second',
|
||||
indexOffset
|
||||
)
|
||||
).toBe(
|
||||
`The speed is between _PARAM${1 + indexOffset}_ and _PARAM${2 +
|
||||
indexOffset}_ pixels per second`
|
||||
);
|
||||
});
|
||||
it(`can shift 2 parameters with jumbled indexes by ${indexOffset}`, () => {
|
||||
expect(
|
||||
shiftSentenceParamIndexes(
|
||||
'The speed is between _PARAM3_ and _PARAM2_ pixels per second',
|
||||
indexOffset
|
||||
)
|
||||
).toBe(
|
||||
`The speed is between _PARAM${3 + indexOffset}_ and _PARAM${2 +
|
||||
indexOffset}_ pixels per second`
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
@@ -50,6 +50,12 @@ const mangleName = (name: string) => {
|
||||
return caseSensitiveSlug(name, '_', []);
|
||||
};
|
||||
|
||||
const getExtensionCodeNamespacePrefix = (
|
||||
eventsFunctionsExtension: gdEventsFunctionsExtension
|
||||
) => {
|
||||
return 'gdjs.evtsExt__' + mangleName(eventsFunctionsExtension.getName());
|
||||
};
|
||||
|
||||
/** Generate the namespace for a free function. */
|
||||
const getFreeFunctionCodeNamespace = (
|
||||
eventsFunction: gdEventsFunction,
|
||||
@@ -58,6 +64,18 @@ const getFreeFunctionCodeNamespace = (
|
||||
return codeNamespacePrefix + '__' + mangleName(eventsFunction.getName());
|
||||
};
|
||||
|
||||
export const getFreeFunctionCodeName = (
|
||||
eventsFunctionsExtension: gdEventsFunctionsExtension,
|
||||
eventsFunction: gdEventsFunction
|
||||
) => {
|
||||
return (
|
||||
getFreeFunctionCodeNamespace(
|
||||
eventsFunction,
|
||||
getExtensionCodeNamespacePrefix(eventsFunctionsExtension)
|
||||
) + '.func'
|
||||
);
|
||||
};
|
||||
|
||||
/** Generate the namespace for a behavior function. */
|
||||
const getBehaviorFunctionCodeNamespace = (
|
||||
eventsBasedBehavior: gdEventsBasedBehavior,
|
||||
@@ -248,7 +266,10 @@ const generateFreeFunction = (
|
||||
codeGenerationContext: CodeGenerationContext
|
||||
): Promise<{
|
||||
functionFile: string,
|
||||
functionMetadata: gdInstructionMetadata | gdExpressionMetadata,
|
||||
functionMetadata:
|
||||
| gdInstructionMetadata
|
||||
| gdExpressionMetadata
|
||||
| gdMultipleInstructionMetadata,
|
||||
}> => {
|
||||
const instructionOrExpression = declareInstructionOrExpressionMetadata(
|
||||
extension,
|
||||
@@ -257,7 +278,12 @@ const generateFreeFunction = (
|
||||
);
|
||||
// By convention, first parameter is always the Runtime Scene.
|
||||
instructionOrExpression.addCodeOnlyParameter('currentScene', '');
|
||||
declareEventsFunctionParameters(eventsFunction, instructionOrExpression);
|
||||
declareEventsFunctionParameters(
|
||||
eventsFunctionsExtension,
|
||||
eventsFunction,
|
||||
instructionOrExpression,
|
||||
0
|
||||
);
|
||||
|
||||
// Hide "lifecycle" functions as they are called automatically by
|
||||
// the game engine.
|
||||
@@ -272,17 +298,16 @@ const generateFreeFunction = (
|
||||
);
|
||||
const functionName = codeNamespace + '.func';
|
||||
|
||||
const codeExtraInformation = instructionOrExpression.getCodeExtraInformation();
|
||||
const functionFile = options.eventsFunctionCodeWriter.getIncludeFileFor(
|
||||
functionName
|
||||
);
|
||||
codeExtraInformation
|
||||
instructionOrExpression
|
||||
.setIncludeFile(functionFile)
|
||||
.setFunctionName(functionName);
|
||||
|
||||
// Always include the extension include files when using a free function.
|
||||
codeGenerationContext.extensionIncludeFiles.forEach(includeFile => {
|
||||
codeExtraInformation.addIncludeFile(includeFile);
|
||||
instructionOrExpression.addIncludeFile(includeFile);
|
||||
});
|
||||
|
||||
if (!options.skipCodeGeneration) {
|
||||
@@ -291,6 +316,7 @@ const generateFreeFunction = (
|
||||
project
|
||||
);
|
||||
const code = eventsFunctionsExtensionCodeGenerator.generateFreeEventsFunctionCompleteCode(
|
||||
eventsFunctionsExtension,
|
||||
eventsFunction,
|
||||
codeNamespace,
|
||||
includeFiles,
|
||||
@@ -307,7 +333,7 @@ const generateFreeFunction = (
|
||||
.toNewVectorString()
|
||||
.toJSArray()
|
||||
.forEach((includeFile: string) => {
|
||||
codeExtraInformation.addIncludeFile(includeFile);
|
||||
instructionOrExpression.addIncludeFile(includeFile);
|
||||
});
|
||||
|
||||
includeFiles.delete();
|
||||
@@ -338,7 +364,10 @@ const generateFreeFunction = (
|
||||
const applyFunctionIncludeFilesDependencyTransitivity = (
|
||||
functionInfos: Array<{
|
||||
functionFile: string,
|
||||
functionMetadata: gdInstructionMetadata | gdExpressionMetadata,
|
||||
functionMetadata:
|
||||
| gdInstructionMetadata
|
||||
| gdExpressionMetadata
|
||||
| gdMultipleInstructionMetadata,
|
||||
}>
|
||||
): void => {
|
||||
// Note that the iteration order doesn't matter, for instance for:
|
||||
@@ -362,12 +391,7 @@ const applyFunctionIncludeFilesDependencyTransitivity = (
|
||||
// c -> d
|
||||
const includeFileSets = functionInfos.map(
|
||||
functionInfo =>
|
||||
new Set(
|
||||
functionInfo.functionMetadata
|
||||
.getCodeExtraInformation()
|
||||
.getIncludeFiles()
|
||||
.toJSArray()
|
||||
)
|
||||
new Set(functionInfo.functionMetadata.getIncludeFiles().toJSArray())
|
||||
);
|
||||
// For any function A of the extension...
|
||||
for (let index = 0; index < functionInfos.length; index++) {
|
||||
@@ -376,9 +400,7 @@ const applyFunctionIncludeFilesDependencyTransitivity = (
|
||||
|
||||
// ...and any function B of the extension...
|
||||
for (let otherIndex = 0; otherIndex < functionInfos.length; otherIndex++) {
|
||||
const otherCodeExtraInformation = functionInfos[
|
||||
otherIndex
|
||||
].functionMetadata.getCodeExtraInformation();
|
||||
const otherFunctionMetadata = functionInfos[otherIndex].functionMetadata;
|
||||
const otherIncludeFileSet = includeFileSets[otherIndex];
|
||||
// ...where function B depends on function A...
|
||||
if (otherIncludeFileSet.has(functionIncludeFile)) {
|
||||
@@ -386,7 +408,7 @@ const applyFunctionIncludeFilesDependencyTransitivity = (
|
||||
includeFiles.forEach(includeFile => {
|
||||
if (!otherIncludeFileSet.has(includeFile)) {
|
||||
otherIncludeFileSet.add(includeFile);
|
||||
otherCodeExtraInformation.addIncludeFile(includeFile);
|
||||
otherFunctionMetadata.addIncludeFile(includeFile);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -450,7 +472,12 @@ function generateBehavior(
|
||||
eventsBasedBehavior,
|
||||
eventsFunction
|
||||
);
|
||||
declareEventsFunctionParameters(eventsFunction, instructionOrExpression);
|
||||
declareEventsFunctionParameters(
|
||||
eventsFunctionsContainer,
|
||||
eventsFunction,
|
||||
instructionOrExpression,
|
||||
2
|
||||
);
|
||||
|
||||
// Hide "lifecycle" methods as they are called automatically by
|
||||
// the game engine.
|
||||
@@ -460,8 +487,7 @@ function generateBehavior(
|
||||
|
||||
if (eventsFunction.isPrivate()) instructionOrExpression.setPrivate();
|
||||
|
||||
const codeExtraInformation = instructionOrExpression.getCodeExtraInformation();
|
||||
codeExtraInformation
|
||||
instructionOrExpression
|
||||
.setIncludeFile(includeFile)
|
||||
.setFunctionName(eventsFunctionMangledName);
|
||||
});
|
||||
@@ -567,7 +593,12 @@ function generateObject(
|
||||
eventsBasedObject,
|
||||
eventsFunction
|
||||
);
|
||||
declareEventsFunctionParameters(eventsFunction, instructionOrExpression);
|
||||
declareEventsFunctionParameters(
|
||||
eventsFunctionsContainer,
|
||||
eventsFunction,
|
||||
instructionOrExpression,
|
||||
1
|
||||
);
|
||||
|
||||
// Hide "lifecycle" methods as they are called automatically by
|
||||
// the game engine.
|
||||
@@ -577,8 +608,7 @@ function generateObject(
|
||||
|
||||
if (eventsFunction.isPrivate()) instructionOrExpression.setPrivate();
|
||||
|
||||
const codeExtraInformation = instructionOrExpression.getCodeExtraInformation();
|
||||
codeExtraInformation
|
||||
instructionOrExpression
|
||||
.setIncludeFile(includeFile)
|
||||
.setFunctionName(eventsFunctionMangledName);
|
||||
});
|
||||
|
@@ -145,6 +145,7 @@ export default class EventsFunctionsList extends React.Component<Props, State> {
|
||||
default:
|
||||
return 'res/functions/function.svg';
|
||||
case gd.EventsFunction.Action:
|
||||
case gd.EventsFunction.ActionWithOperator:
|
||||
switch (eventsFunction.getName()) {
|
||||
default:
|
||||
return 'res/functions/action.svg';
|
||||
@@ -178,8 +179,7 @@ export default class EventsFunctionsList extends React.Component<Props, State> {
|
||||
case gd.EventsFunction.Condition:
|
||||
return 'res/functions/condition.svg';
|
||||
case gd.EventsFunction.Expression:
|
||||
return 'res/functions/expression.svg';
|
||||
case gd.EventsFunction.StringExpression:
|
||||
case gd.EventsFunction.ExpressionAndCondition:
|
||||
return 'res/functions/expression.svg';
|
||||
}
|
||||
};
|
||||
|
@@ -286,9 +286,11 @@ export default class EventsFunctionExtractorDialog extends React.Component<
|
||||
) : null}
|
||||
</Column>
|
||||
<EventsFunctionPropertiesEditor
|
||||
project={project}
|
||||
eventsFunction={eventsFunction}
|
||||
eventsBasedBehavior={null}
|
||||
eventsBasedObject={null}
|
||||
eventsFunctionsContainer={null}
|
||||
onConfigurationUpdated={() => {
|
||||
// Force re-running logic to see if Create button is disabled.
|
||||
this.forceUpdate();
|
||||
@@ -302,6 +304,7 @@ export default class EventsFunctionExtractorDialog extends React.Component<
|
||||
eventsFunction={eventsFunction}
|
||||
eventsBasedBehavior={null}
|
||||
eventsBasedObject={null}
|
||||
eventsFunctionsContainer={null}
|
||||
onParametersUpdated={() => {
|
||||
// Force the dialog to adapt its size
|
||||
this.forceUpdate();
|
||||
|
@@ -3,13 +3,16 @@ import { mapVector } from '../../Utils/MapFor';
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
export const enumerateParametersUsableInExpressions = (
|
||||
eventsFunctionsContainer: gdEventsFunctionsContainer,
|
||||
eventsFunction: gdEventsFunction
|
||||
): Array<gdParameterMetadata> => {
|
||||
return mapVector(eventsFunction.getParameters(), parameterMetadata =>
|
||||
parameterMetadata.isCodeOnly() ||
|
||||
gd.ParameterMetadata.isObject(parameterMetadata.getType()) ||
|
||||
gd.ParameterMetadata.isBehavior(parameterMetadata.getType())
|
||||
? null
|
||||
: parameterMetadata
|
||||
return mapVector(
|
||||
eventsFunction.getParametersForEvents(eventsFunctionsContainer),
|
||||
parameterMetadata =>
|
||||
parameterMetadata.isCodeOnly() ||
|
||||
gd.ParameterMetadata.isObject(parameterMetadata.getType()) ||
|
||||
gd.ParameterMetadata.isBehavior(parameterMetadata.getType())
|
||||
? null
|
||||
: parameterMetadata
|
||||
).filter(Boolean);
|
||||
};
|
||||
|
@@ -16,15 +16,22 @@ export default class FunctionParameterNameField extends Component<
|
||||
}
|
||||
|
||||
render() {
|
||||
const parameterNames: Array<ExpressionAutocompletion> = this.props.scope
|
||||
.eventsFunction
|
||||
? enumerateParametersUsableInExpressions(
|
||||
this.props.scope.eventsFunction
|
||||
).map(parameterMetadata => ({
|
||||
kind: 'Text',
|
||||
completion: `"${parameterMetadata.getName()}"`,
|
||||
}))
|
||||
: [];
|
||||
const eventsBasedEntity =
|
||||
this.props.scope.eventsBasedBehavior ||
|
||||
this.props.scope.eventsBasedObject;
|
||||
const functionsContainer = eventsBasedEntity
|
||||
? eventsBasedEntity.getEventsFunctions()
|
||||
: this.props.scope.eventsFunctionsExtension;
|
||||
const parameterNames: Array<ExpressionAutocompletion> =
|
||||
this.props.scope.eventsFunction && functionsContainer
|
||||
? enumerateParametersUsableInExpressions(
|
||||
functionsContainer,
|
||||
this.props.scope.eventsFunction
|
||||
).map(parameterMetadata => ({
|
||||
kind: 'Text',
|
||||
completion: `"${parameterMetadata.getName()}"`,
|
||||
}))
|
||||
: [];
|
||||
|
||||
return (
|
||||
<GenericExpressionField
|
||||
|
@@ -357,8 +357,14 @@ const getAutocompletionsForText = function(
|
||||
return [];
|
||||
}
|
||||
} else if (type === 'functionParameterName') {
|
||||
if (scope.eventsFunction) {
|
||||
const eventsBasedEntity =
|
||||
scope.eventsBasedBehavior || scope.eventsBasedObject;
|
||||
const functionsContainer = eventsBasedEntity
|
||||
? eventsBasedEntity.getEventsFunctions()
|
||||
: scope.eventsFunctionsExtension;
|
||||
if (scope.eventsFunction && functionsContainer) {
|
||||
autocompletionTexts = enumerateParametersUsableInExpressions(
|
||||
functionsContainer,
|
||||
scope.eventsFunction
|
||||
).map(parameterMetadata => `"${parameterMetadata.getName()}"`);
|
||||
}
|
||||
|
@@ -13,11 +13,13 @@ import Add from '@material-ui/icons/Add';
|
||||
type StringArrayEditorProps = {|
|
||||
extraInfo: Array<string>,
|
||||
setExtraInfo: (Array<string>) => void,
|
||||
disabled?: boolean,
|
||||
|};
|
||||
|
||||
const StringArrayEditor = ({
|
||||
extraInfo,
|
||||
setExtraInfo,
|
||||
disabled,
|
||||
}: StringArrayEditorProps) => {
|
||||
const updateExtraInfo = () => setExtraInfo(extraInfo);
|
||||
|
||||
@@ -27,6 +29,7 @@ const StringArrayEditor = ({
|
||||
{extraInfo.map((item, index) => (
|
||||
<Line key={index} justifyContent="flex-end" expand>
|
||||
<SemiControlledTextField
|
||||
disabled={disabled}
|
||||
commitOnBlur
|
||||
value={item}
|
||||
onChange={text => {
|
||||
@@ -36,6 +39,7 @@ const StringArrayEditor = ({
|
||||
fullWidth
|
||||
/>
|
||||
<IconButton
|
||||
disabled={disabled}
|
||||
tooltip={t`Delete option`}
|
||||
onClick={() => {
|
||||
extraInfo.splice(index, 1);
|
||||
@@ -49,6 +53,7 @@ const StringArrayEditor = ({
|
||||
|
||||
<Line justifyContent="flex-end" expand>
|
||||
<RaisedButton
|
||||
disabled={disabled}
|
||||
primary
|
||||
onClick={() => {
|
||||
extraInfo.push('New Option');
|
||||
|
@@ -1,11 +1,11 @@
|
||||
// @flow
|
||||
// Note: this file does not use export/imports and use Flow comments to allow its usage from Node.js
|
||||
|
||||
const mapFor = /*:: <T>*/ (
|
||||
const mapFor = /*:: <T> */ (
|
||||
start /*: number */,
|
||||
end /*: number */,
|
||||
func /*: (number) => T */
|
||||
) /*:Array<T> */ => {
|
||||
) /*: Array<T> */ => {
|
||||
const result = [];
|
||||
for (let i = start; i < end; i++) {
|
||||
result.push(func(i));
|
||||
@@ -13,11 +13,11 @@ const mapFor = /*:: <T>*/ (
|
||||
return result;
|
||||
};
|
||||
|
||||
const mapReverseFor = /*:: <T>*/ (
|
||||
const mapReverseFor = /*:: <T> */ (
|
||||
start /*: number */,
|
||||
end /*: number */,
|
||||
func /*: (number) => T */
|
||||
) /*:Array<T> */ => {
|
||||
) /*: Array<T> */ => {
|
||||
const result = [];
|
||||
for (let i = end - 1; i >= start; i--) {
|
||||
result.push(func(i));
|
||||
@@ -32,10 +32,10 @@ type CppVector<T> = {
|
||||
}
|
||||
*/
|
||||
|
||||
const mapVector = /*:: <T, U>*/ (
|
||||
const mapVector = /*:: <T, U> */ (
|
||||
cppVector /*: CppVector<T> */,
|
||||
func /*: (T, number) => U */
|
||||
) /*:Array<U> */ => {
|
||||
) /*: Array<U> */ => {
|
||||
return mapFor(0, cppVector.size(), i => func(cppVector.at(i), i));
|
||||
};
|
||||
|
||||
|
@@ -27,6 +27,7 @@ export const DefaultFreeFunction = () => (
|
||||
eventsFunction={testProject.testEventsFunction}
|
||||
eventsBasedBehavior={null}
|
||||
eventsBasedObject={null}
|
||||
eventsFunctionsContainer={testProject.testEventsFunctionsExtension}
|
||||
onParametersOrGroupsUpdated={action('Parameters or groups were updated')}
|
||||
/>
|
||||
</FixedHeightFlexContainer>
|
||||
@@ -42,6 +43,7 @@ export const DefaultBehaviorFunction = () => (
|
||||
eventsFunction={testProject.testBehaviorEventsFunction}
|
||||
eventsBasedBehavior={testProject.testEventsBasedBehavior}
|
||||
eventsBasedObject={null}
|
||||
eventsFunctionsContainer={testProject.testEventsBasedBehavior.getEventsFunctions()}
|
||||
onParametersOrGroupsUpdated={action('Parameters or groups were updated')}
|
||||
/>
|
||||
</FixedHeightFlexContainer>
|
||||
@@ -57,6 +59,7 @@ export const DefaultBehaviorLifecycleFunction = () => (
|
||||
eventsFunction={testProject.testBehaviorLifecycleEventsFunction}
|
||||
eventsBasedBehavior={testProject.testEventsBasedBehavior}
|
||||
eventsBasedObject={null}
|
||||
eventsFunctionsContainer={testProject.testEventsBasedBehavior.getEventsFunctions()}
|
||||
onParametersOrGroupsUpdated={action('Parameters or groups were updated')}
|
||||
/>
|
||||
</FixedHeightFlexContainer>
|
||||
@@ -72,6 +75,7 @@ export const DefaultObjectFunction = () => (
|
||||
eventsFunction={testProject.testObjectEventsFunction}
|
||||
eventsBasedBehavior={null}
|
||||
eventsBasedObject={testProject.testEventsBasedObject}
|
||||
eventsFunctionsContainer={testProject.testEventsBasedObject.getEventsFunctions()}
|
||||
onParametersOrGroupsUpdated={action('Parameters or groups were updated')}
|
||||
/>
|
||||
</FixedHeightFlexContainer>
|
||||
|
@@ -88,21 +88,14 @@ import PlaceholderLoader from '../UI/PlaceholderLoader';
|
||||
import ColorField from '../UI/ColorField';
|
||||
import EmptyMessage from '../UI/EmptyMessage';
|
||||
import BackgroundText from '../UI/BackgroundText';
|
||||
import EventsFunctionConfigurationEditor from '../EventsFunctionsExtensionEditor/EventsFunctionConfigurationEditor';
|
||||
import EventsFunctionsList from '../EventsFunctionsList';
|
||||
import EventsFunctionsExtensionEditor from '../EventsFunctionsExtensionEditor';
|
||||
import OptionsEditorDialog from '../EventsFunctionsExtensionEditor/OptionsEditorDialog';
|
||||
import ProjectManager from '../ProjectManager';
|
||||
import AlertMessage from '../UI/AlertMessage';
|
||||
import ChangelogRenderer from '../MainFrame/Changelog/ChangelogRenderer';
|
||||
import ChangelogDialog from '../MainFrame/Changelog/ChangelogDialog';
|
||||
import EventsFunctionExtractorDialog from '../EventsSheet/EventsFunctionExtractor/EventsFunctionExtractorDialog';
|
||||
import FixedHeightFlexContainer from './FixedHeightFlexContainer';
|
||||
import EventsBasedBehaviorEditor from '../EventsBasedBehaviorEditor';
|
||||
import EventsBasedBehaviorEditorDialog from '../EventsBasedBehaviorEditor/EventsBasedBehaviorEditorDialog';
|
||||
import BehaviorTypeSelector from '../BehaviorTypeSelector';
|
||||
import ObjectTypeSelector from '../ObjectTypeSelector';
|
||||
import EventsFunctionsExtensionsProvider from '../EventsFunctionsExtensionsLoader/EventsFunctionsExtensionsProvider';
|
||||
import SemiControlledTextField from '../UI/SemiControlledTextField';
|
||||
import SemiControlledAutoComplete from '../UI/SemiControlledAutoComplete';
|
||||
import SemiControlledMultiAutoComplete from '../UI/SemiControlledMultiAutoComplete';
|
||||
@@ -121,7 +114,6 @@ import EditorMosaic from '../UI/EditorMosaic';
|
||||
import FlatButton from '../UI/FlatButton';
|
||||
import EditorMosaicPlayground from './EditorMosaicPlayground';
|
||||
import EditorNavigator from '../UI/EditorMosaic/EditorNavigator';
|
||||
import ChooseEventsFunctionsExtensionEditor from '../EventsFunctionsExtensionEditor/ChooseEventsFunctionsExtensionEditor';
|
||||
import PropertiesEditor from '../PropertiesEditor';
|
||||
import { OpenConfirmDialog } from '../ProjectsStorage/OpenConfirmDialog';
|
||||
import BrowserPreviewErrorDialog from '../Export/BrowserExporters/BrowserS3PreviewLauncher/BrowserPreviewErrorDialog';
|
||||
|
Reference in New Issue
Block a user