mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
44 Commits
v5.1.148
...
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 | ||
![]() |
71f20d7852 | ||
![]() |
9d121d0085 | ||
![]() |
6292e338bc | ||
![]() |
c5eb0bcc00 | ||
![]() |
a732fda4d9 | ||
![]() |
398bff8492 | ||
![]() |
f30e92a953 | ||
![]() |
8210c25acb | ||
![]() |
6a13940e17 | ||
![]() |
622aa7c08c | ||
![]() |
a71558a490 | ||
![]() |
37539aa788 | ||
![]() |
789f819f25 | ||
![]() |
52ebfb8100 | ||
![]() |
ecc5c689d2 | ||
![]() |
5b1e169557 |
@@ -43,7 +43,7 @@ gd::String EventsCodeGenerator::GenerateRelationalOperatorCall(
|
||||
std::size_t relationalOperatorIndex = instrInfos.parameters.size();
|
||||
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
|
||||
++i) {
|
||||
if (instrInfos.parameters[i].type == "relationalOperator")
|
||||
if (instrInfos.parameters[i].GetType() == "relationalOperator")
|
||||
relationalOperatorIndex = i;
|
||||
}
|
||||
// Ensure that there is at least one parameter after the relational operator
|
||||
@@ -95,7 +95,7 @@ gd::String EventsCodeGenerator::GenerateOperatorCall(
|
||||
std::size_t operatorIndex = instrInfos.parameters.size();
|
||||
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
|
||||
++i) {
|
||||
if (instrInfos.parameters[i].type == "operator") operatorIndex = i;
|
||||
if (instrInfos.parameters[i].GetType() == "operator") operatorIndex = i;
|
||||
}
|
||||
|
||||
// Ensure that there is at least one parameter after the operator
|
||||
@@ -164,7 +164,7 @@ gd::String EventsCodeGenerator::GenerateCompoundOperatorCall(
|
||||
std::size_t operatorIndex = instrInfos.parameters.size();
|
||||
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
|
||||
++i) {
|
||||
if (instrInfos.parameters[i].type == "operator") operatorIndex = i;
|
||||
if (instrInfos.parameters[i].GetType() == "operator") operatorIndex = i;
|
||||
}
|
||||
|
||||
// Ensure that there is at least one parameter after the operator
|
||||
@@ -215,7 +215,7 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
|
||||
std::size_t operatorIndex = instrInfos.parameters.size();
|
||||
for (std::size_t i = startFromArgument; i < instrInfos.parameters.size();
|
||||
++i) {
|
||||
if (instrInfos.parameters[i].type == "operator") operatorIndex = i;
|
||||
if (instrInfos.parameters[i].GetType() == "operator") operatorIndex = i;
|
||||
}
|
||||
|
||||
// Ensure that there is at least one parameter after the operator
|
||||
@@ -293,7 +293,7 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
|
||||
// Verify that there are no mismatchs between object type in parameters.
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].type)) {
|
||||
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType())) {
|
||||
gd::String objectInParameter =
|
||||
condition.GetParameter(pNb).GetPlainString();
|
||||
|
||||
@@ -303,11 +303,11 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(
|
||||
objectInParameter)) {
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!instrInfos.parameters[pNb].supplementaryInformation.empty() &&
|
||||
} else if (!instrInfos.parameters[pNb].GetExtraInfo().empty() &&
|
||||
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(),
|
||||
GetObjectsAndGroups(),
|
||||
objectInParameter) !=
|
||||
instrInfos.parameters[pNb].supplementaryInformation) {
|
||||
instrInfos.parameters[pNb].GetExtraInfo()) {
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
@@ -485,7 +485,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
|
||||
// Verify that there are no mismatchs between object type in parameters.
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].type)) {
|
||||
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType())) {
|
||||
gd::String objectInParameter = action.GetParameter(pNb).GetPlainString();
|
||||
if (!GetObjectsAndGroups().HasObjectNamed(objectInParameter) &&
|
||||
!GetGlobalObjectsAndGroups().HasObjectNamed(objectInParameter) &&
|
||||
@@ -493,11 +493,11 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
!GetGlobalObjectsAndGroups().GetObjectGroups().Has(
|
||||
objectInParameter)) {
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!instrInfos.parameters[pNb].supplementaryInformation.empty() &&
|
||||
} else if (!instrInfos.parameters[pNb].GetExtraInfo().empty() &&
|
||||
gd::GetTypeOfObject(GetGlobalObjectsAndGroups(),
|
||||
GetObjectsAndGroups(),
|
||||
objectInParameter) !=
|
||||
instrInfos.parameters[pNb].supplementaryInformation) {
|
||||
instrInfos.parameters[pNb].GetExtraInfo()) {
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
@@ -679,21 +679,21 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
supplementaryParametersTypes) {
|
||||
gd::String argOutput;
|
||||
|
||||
if (ParameterMetadata::IsExpression("number", metadata.type)) {
|
||||
if (ParameterMetadata::IsExpression("number", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, "number", parameter, lastObjectName);
|
||||
} else if (ParameterMetadata::IsExpression("string", metadata.type)) {
|
||||
} else if (ParameterMetadata::IsExpression("string", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, "string", parameter, lastObjectName);
|
||||
} else if (ParameterMetadata::IsExpression("variable", metadata.type)) {
|
||||
} else if (ParameterMetadata::IsExpression("variable", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, metadata.type, parameter, lastObjectName);
|
||||
} else if (ParameterMetadata::IsObject(metadata.type)) {
|
||||
*this, context, metadata.GetType(), parameter, lastObjectName);
|
||||
} else if (ParameterMetadata::IsObject(metadata.GetType())) {
|
||||
// It would be possible to run a gd::ExpressionCodeGenerator if later
|
||||
// objects can have nested objects, or function returning objects.
|
||||
argOutput =
|
||||
GenerateObject(parameter.GetPlainString(), metadata.type, context);
|
||||
} else if (metadata.type == "relationalOperator") {
|
||||
GenerateObject(parameter.GetPlainString(), metadata.GetType(), context);
|
||||
} else if (metadata.GetType() == "relationalOperator") {
|
||||
auto parameterString = parameter.GetPlainString();
|
||||
argOutput += parameterString == "=" ? "==" : parameterString;
|
||||
if (argOutput != "==" && argOutput != "<" && argOutput != ">" &&
|
||||
@@ -703,7 +703,7 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
}
|
||||
|
||||
argOutput = "\"" + argOutput + "\"";
|
||||
} else if (metadata.type == "operator") {
|
||||
} else if (metadata.GetType() == "operator") {
|
||||
argOutput += parameter.GetPlainString();
|
||||
if (argOutput != "=" && argOutput != "+" && argOutput != "-" &&
|
||||
argOutput != "/" && argOutput != "*") {
|
||||
@@ -712,28 +712,28 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
}
|
||||
|
||||
argOutput = "\"" + argOutput + "\"";
|
||||
} else if (ParameterMetadata::IsBehavior(metadata.type)) {
|
||||
} else if (ParameterMetadata::IsBehavior(metadata.GetType())) {
|
||||
argOutput = GenerateGetBehaviorNameCode(parameter.GetPlainString());
|
||||
} else if (metadata.type == "key") {
|
||||
} else if (metadata.GetType() == "key") {
|
||||
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
|
||||
} else if (metadata.type == "audioResource" ||
|
||||
metadata.type == "bitmapFontResource" ||
|
||||
metadata.type == "fontResource" ||
|
||||
metadata.type == "imageResource" ||
|
||||
metadata.type == "jsonResource" ||
|
||||
metadata.type == "videoResource" ||
|
||||
} else if (metadata.GetType() == "audioResource" ||
|
||||
metadata.GetType() == "bitmapFontResource" ||
|
||||
metadata.GetType() == "fontResource" ||
|
||||
metadata.GetType() == "imageResource" ||
|
||||
metadata.GetType() == "jsonResource" ||
|
||||
metadata.GetType() == "videoResource" ||
|
||||
// Deprecated, old parameter names:
|
||||
metadata.type == "password" || metadata.type == "musicfile" ||
|
||||
metadata.type == "soundfile" || metadata.type == "police") {
|
||||
metadata.GetType() == "password" || metadata.GetType() == "musicfile" ||
|
||||
metadata.GetType() == "soundfile" || metadata.GetType() == "police") {
|
||||
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
|
||||
} else if (metadata.type == "mouse") {
|
||||
} else if (metadata.GetType() == "mouse") {
|
||||
argOutput = "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
|
||||
} else if (metadata.type == "yesorno") {
|
||||
} else if (metadata.GetType() == "yesorno") {
|
||||
auto parameterString = parameter.GetPlainString();
|
||||
argOutput += (parameterString == "yes" || parameterString == "oui")
|
||||
? GenerateTrue()
|
||||
: GenerateFalse();
|
||||
} else if (metadata.type == "trueorfalse") {
|
||||
} else if (metadata.GetType() == "trueorfalse") {
|
||||
auto parameterString = parameter.GetPlainString();
|
||||
// This is duplicated in AdvancedExtension.cpp for GDJS
|
||||
argOutput += (parameterString == "True" || parameterString == "Vrai")
|
||||
@@ -741,21 +741,21 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
: GenerateFalse();
|
||||
}
|
||||
// Code only parameter type
|
||||
else if (metadata.type == "inlineCode") {
|
||||
argOutput += metadata.supplementaryInformation;
|
||||
else if (metadata.GetType() == "inlineCode") {
|
||||
argOutput += metadata.GetExtraInfo();
|
||||
} else {
|
||||
// Try supplementary types if provided
|
||||
if (supplementaryParametersTypes) {
|
||||
for (std::size_t i = 0; i < supplementaryParametersTypes->size(); ++i) {
|
||||
if ((*supplementaryParametersTypes)[i].first == metadata.type)
|
||||
if ((*supplementaryParametersTypes)[i].first == metadata.GetType())
|
||||
argOutput += (*supplementaryParametersTypes)[i].second;
|
||||
}
|
||||
}
|
||||
|
||||
// Type unknown
|
||||
if (argOutput.empty()) {
|
||||
if (!metadata.type.empty())
|
||||
cout << "Warning: Unknown type of parameter \"" << metadata.type
|
||||
if (!metadata.GetType().empty())
|
||||
cout << "Warning: Unknown type of parameter \"" << metadata.GetType()
|
||||
<< "\"." << std::endl;
|
||||
argOutput += "\"" + ConvertToString(parameter.GetPlainString()) + "\"";
|
||||
}
|
||||
@@ -1030,7 +1030,7 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
|
||||
for (std::size_t i = 0; i < instrInfos.parameters.size();
|
||||
++i) // Some conditions already have a "conditionInverted" parameter
|
||||
{
|
||||
if (instrInfos.parameters[i].type == "conditionInverted")
|
||||
if (instrInfos.parameters[i].GetType() == "conditionInverted")
|
||||
conditionAlreadyTakeCareOfInversion = true;
|
||||
}
|
||||
if (!conditionAlreadyTakeCareOfInversion && conditionInverted)
|
||||
@@ -1051,7 +1051,7 @@ gd::String EventsCodeGenerator::GenerateObjectCondition(
|
||||
// Prepare call
|
||||
// Add a static_cast if necessary
|
||||
gd::String objectFunctionCallNamePart =
|
||||
(!instrInfos.parameters[0].supplementaryInformation.empty())
|
||||
(!instrInfos.parameters[0].GetExtraInfo().empty())
|
||||
? "static_cast<" + objInfo.className + "*>(" +
|
||||
GetObjectListName(objectName, context) + "[i])->" +
|
||||
instrInfos.codeExtraInformation.functionCallName
|
||||
|
@@ -184,8 +184,8 @@ void EventsListSerialization::UpdateInstructionsFromGD2x(
|
||||
for (std::size_t j = 0;
|
||||
j < parameters.size() && j < metadata.parameters.size();
|
||||
++j) {
|
||||
if (metadata.parameters[j].type == "relationalOperator" ||
|
||||
metadata.parameters[j].type == "operator") {
|
||||
if (metadata.parameters[j].GetType() == "relationalOperator" ||
|
||||
metadata.parameters[j].GetType() == "operator") {
|
||||
if (j == parameters.size() - 1) {
|
||||
std::cout << "ERROR: No more parameters after a [relational]operator "
|
||||
"when trying to update an instruction from GD2.x";
|
||||
|
@@ -37,22 +37,24 @@ gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
|
||||
const gd::String& supplementaryInformation,
|
||||
bool parameterIsOptional) {
|
||||
gd::ParameterMetadata info;
|
||||
info.type = type;
|
||||
info.SetType(type);
|
||||
info.description = description;
|
||||
info.codeOnly = false;
|
||||
info.optional = parameterIsOptional;
|
||||
info.supplementaryInformation =
|
||||
info.SetOptional(parameterIsOptional);
|
||||
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 +
|
||||
supplementaryInformation //... so prefix it with the extension
|
||||
// namespace.
|
||||
)
|
||||
: supplementaryInformation; // Otherwise don't change anything
|
||||
: supplementaryInformation); // Otherwise don't change anything
|
||||
|
||||
// TODO: Assert against supplementaryInformation === "emsc" (when running with
|
||||
// Emscripten), and warn about a missing argument when calling addParameter.
|
||||
@@ -64,9 +66,9 @@ gd::ExpressionMetadata& ExpressionMetadata::AddParameter(
|
||||
gd::ExpressionMetadata& ExpressionMetadata::AddCodeOnlyParameter(
|
||||
const gd::String& type, const gd::String& supplementaryInformation) {
|
||||
gd::ParameterMetadata info;
|
||||
info.type = type;
|
||||
info.SetType(type);
|
||||
info.codeOnly = true;
|
||||
info.supplementaryInformation = supplementaryInformation;
|
||||
info.SetExtraInfo(supplementaryInformation);
|
||||
|
||||
parameters.push_back(info);
|
||||
return *this;
|
||||
|
@@ -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;
|
||||
|
||||
|
@@ -55,15 +55,17 @@ InstructionMetadata& InstructionMetadata::AddParameter(
|
||||
const gd::String& supplementaryInformation,
|
||||
bool parameterIsOptional) {
|
||||
ParameterMetadata info;
|
||||
info.type = type;
|
||||
info.SetType(type);
|
||||
info.description = description;
|
||||
info.codeOnly = false;
|
||||
info.optional = parameterIsOptional;
|
||||
info.supplementaryInformation =
|
||||
info.SetOptional(parameterIsOptional);
|
||||
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 +
|
||||
@@ -71,7 +73,7 @@ InstructionMetadata& InstructionMetadata::AddParameter(
|
||||
// extension
|
||||
// namespace.
|
||||
)
|
||||
: supplementaryInformation; // Otherwise don't change anything
|
||||
: supplementaryInformation); // Otherwise don't change anything
|
||||
|
||||
// TODO: Assert against supplementaryInformation === "emsc" (when running with
|
||||
// Emscripten), and warn about a missing argument when calling addParameter.
|
||||
@@ -83,17 +85,19 @@ InstructionMetadata& InstructionMetadata::AddParameter(
|
||||
InstructionMetadata& InstructionMetadata::AddCodeOnlyParameter(
|
||||
const gd::String& type, const gd::String& supplementaryInformation) {
|
||||
ParameterMetadata info;
|
||||
info.type = type;
|
||||
info.SetType(type);
|
||||
info.codeOnly = true;
|
||||
info.supplementaryInformation = supplementaryInformation;
|
||||
info.SetExtraInfo(supplementaryInformation);
|
||||
|
||||
parameters.push_back(info);
|
||||
return *this;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
@@ -233,14 +229,12 @@ class GD_CORE_API ParameterMetadata {
|
||||
|
||||
// TODO: Deprecated public fields. Any direct usage should be moved to
|
||||
// getter/setter.
|
||||
gd::String type; ///< Parameter type
|
||||
gd::String supplementaryInformation; ///< Used if needed
|
||||
bool optional; ///< True if the parameter is optional
|
||||
|
||||
gd::String description; ///< Description shown in editor
|
||||
bool codeOnly; ///< True if parameter is relative to code generation only,
|
||||
///< i.e. must not be shown in editor
|
||||
private:
|
||||
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
|
||||
|
@@ -85,7 +85,7 @@ void ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
const gd::Expression& parameterValue =
|
||||
pNb < parameters.size() ? parameters[pNb].GetPlainString() : "";
|
||||
const gd::Expression& parameterValueOrDefault =
|
||||
parameterValue.GetPlainString().empty() && parameterMetadata.optional
|
||||
parameterValue.GetPlainString().empty() && parameterMetadata.IsOptional()
|
||||
? Expression(parameterMetadata.GetDefaultValue())
|
||||
: parameterValue;
|
||||
|
||||
|
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
|
@@ -120,7 +120,7 @@ bool EventsBehaviorRenamer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
const gd::Expression& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
const gd::String& type = parameterMetadata.type;
|
||||
const gd::String& type = parameterMetadata.GetType();
|
||||
|
||||
if (gd::ParameterMetadata::IsBehavior(type)) {
|
||||
if (lastObjectName == objectName) {
|
||||
|
@@ -149,8 +149,8 @@ class GD_CORE_API IdentifierFinderEventWorker
|
||||
platform, instruction.GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
// The parameter has the searched type...
|
||||
if (instrInfos.parameters[pNb].type == "identifier"
|
||||
&& instrInfos.parameters[pNb].supplementaryInformation == identifierType) {
|
||||
if (instrInfos.parameters[pNb].GetType() == "identifier"
|
||||
&& instrInfos.parameters[pNb].GetExtraInfo() == identifierType) {
|
||||
//...remember the value of the parameter.
|
||||
if (objectName.empty() || lastObjectParameter == objectName) {
|
||||
results.insert(instruction.GetParameter(pNb).GetPlainString());
|
||||
@@ -158,9 +158,9 @@ class GD_CORE_API IdentifierFinderEventWorker
|
||||
}
|
||||
// Search in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type) ||
|
||||
"number", instrInfos.parameters[pNb].GetType()) ||
|
||||
ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
"string", instrInfos.parameters[pNb].GetType())) {
|
||||
auto node = instruction.GetParameter(pNb).GetRootNode();
|
||||
|
||||
IdentifierFinderExpressionNodeWorker searcher(
|
||||
@@ -174,7 +174,7 @@ class GD_CORE_API IdentifierFinderEventWorker
|
||||
}
|
||||
// Remember the value of the last "object" parameter.
|
||||
else if (gd::ParameterMetadata::IsObject(
|
||||
instrInfos.parameters[pNb].type)) {
|
||||
instrInfos.parameters[pNb].GetType())) {
|
||||
lastObjectParameter =
|
||||
instruction.GetParameter(pNb).GetPlainString();
|
||||
}
|
||||
|
@@ -30,7 +30,7 @@ bool EventsLeaderboardsLister::DoVisitInstruction(gd::Instruction& instruction,
|
||||
for (int i = 0; i < instruction.GetParametersCount() &&
|
||||
i < instrInfo.GetParametersCount();
|
||||
++i)
|
||||
if (instrInfo.GetParameter(i).type == "leaderboardId") {
|
||||
if (instrInfo.GetParameter(i).GetType() == "leaderboardId") {
|
||||
leaderboardIds.insert(instruction.GetParameter(i).GetPlainString());
|
||||
}
|
||||
return false;
|
||||
|
@@ -32,7 +32,7 @@ bool EventsLeaderboardsRenamer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
++i) {
|
||||
const gd::ParameterMetadata parameter = instrInfo.GetParameter(i);
|
||||
|
||||
if (parameter.type == "leaderboardId") {
|
||||
if (parameter.GetType() == "leaderboardId") {
|
||||
const gd::String leaderboardId =
|
||||
instruction.GetParameter(i).GetPlainString();
|
||||
|
||||
|
@@ -237,12 +237,12 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
// Replace object's name in parameters
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].type) &&
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
|
||||
actions[aId].GetParameter(pNb).GetPlainString() == oldName)
|
||||
actions[aId].SetParameter(pNb, gd::Expression(newName));
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
"number", instrInfos.parameters[pNb].GetType())) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, project, layout, "number", *node, oldName, newName)) {
|
||||
@@ -252,7 +252,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
"string", instrInfos.parameters[pNb].GetType())) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, project, layout, "string", *node, oldName, newName)) {
|
||||
@@ -291,12 +291,12 @@ bool EventsRefactorer::RenameObjectInConditions(
|
||||
conditions[cId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
// Replace object's name in parameters
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].type) &&
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
|
||||
conditions[cId].GetParameter(pNb).GetPlainString() == oldName)
|
||||
conditions[cId].SetParameter(pNb, gd::Expression(newName));
|
||||
// Replace object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
"number", instrInfos.parameters[pNb].GetType())) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, project, layout, "number", *node, oldName, newName)) {
|
||||
@@ -306,7 +306,7 @@ bool EventsRefactorer::RenameObjectInConditions(
|
||||
}
|
||||
// Replace object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
"string", instrInfos.parameters[pNb].GetType())) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectRenamer::Rename(platform, project, layout, "string", *node, oldName, newName)) {
|
||||
@@ -425,14 +425,14 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
MetadataProvider::GetActionMetadata(platform, actions[aId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
// Find object's name in parameters
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].type) &&
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
|
||||
actions[aId].GetParameter(pNb).GetPlainString() == name) {
|
||||
deleteMe = true;
|
||||
break;
|
||||
}
|
||||
// Find object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
"number", instrInfos.parameters[pNb].GetType())) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "number", *node, name)) {
|
||||
@@ -442,7 +442,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
}
|
||||
// Find object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
"string", instrInfos.parameters[pNb].GetType())) {
|
||||
auto node = actions[aId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "string", *node, name)) {
|
||||
@@ -485,14 +485,14 @@ bool EventsRefactorer::RemoveObjectInConditions(
|
||||
conditions[cId].GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
// Find object's name in parameters
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].type) &&
|
||||
if (gd::ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType()) &&
|
||||
conditions[cId].GetParameter(pNb).GetPlainString() == name) {
|
||||
deleteMe = true;
|
||||
break;
|
||||
}
|
||||
// Find object's name in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type)) {
|
||||
"number", instrInfos.parameters[pNb].GetType())) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "number", *node, name)) {
|
||||
@@ -502,7 +502,7 @@ bool EventsRefactorer::RemoveObjectInConditions(
|
||||
}
|
||||
// Find object's name in text expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
"string", instrInfos.parameters[pNb].GetType())) {
|
||||
auto node = conditions[cId].GetParameter(pNb).GetRootNode();
|
||||
|
||||
if (ExpressionObjectFinder::CheckIfHasObject(platform, globalObjectsContainer, objectsContainer, "string", *node, name)) {
|
||||
|
@@ -148,16 +148,16 @@ class GD_CORE_API VariableFinderEventWorker
|
||||
platform, instruction.GetType());
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
// The parameter has the searched type...
|
||||
if (instrInfos.parameters[pNb].type == parameterType) {
|
||||
if (instrInfos.parameters[pNb].GetType() == parameterType) {
|
||||
//...remember the value of the parameter.
|
||||
if (objectName.empty() || lastObjectParameter == objectName)
|
||||
results.insert(instruction.GetParameter(pNb).GetPlainString());
|
||||
}
|
||||
// Search in expressions
|
||||
else if (ParameterMetadata::IsExpression(
|
||||
"number", instrInfos.parameters[pNb].type) ||
|
||||
"number", instrInfos.parameters[pNb].GetType()) ||
|
||||
ParameterMetadata::IsExpression(
|
||||
"string", instrInfos.parameters[pNb].type)) {
|
||||
"string", instrInfos.parameters[pNb].GetType())) {
|
||||
auto node = instruction.GetParameter(pNb).GetRootNode();
|
||||
|
||||
VariableFinderExpressionNodeWorker searcher(
|
||||
@@ -171,7 +171,7 @@ class GD_CORE_API VariableFinderEventWorker
|
||||
}
|
||||
// Remember the value of the last "object" parameter.
|
||||
else if (gd::ParameterMetadata::IsObject(
|
||||
instrInfos.parameters[pNb].type)) {
|
||||
instrInfos.parameters[pNb].GetType())) {
|
||||
lastObjectParameter =
|
||||
instruction.GetParameter(pNb).GetPlainString();
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@ size_t GetMinimumParametersNumber(
|
||||
size_t initialParameterIndex) {
|
||||
size_t nb = 0;
|
||||
for (std::size_t i = initialParameterIndex; i < parameters.size(); ++i) {
|
||||
if (!parameters[i].optional && !parameters[i].codeOnly) nb++;
|
||||
if (!parameters[i].IsOptional() && !parameters[i].codeOnly) nb++;
|
||||
}
|
||||
|
||||
return nb;
|
||||
|
@@ -150,7 +150,7 @@ bool ExpressionsParameterMover::DoVisitInstruction(gd::Instruction& instruction,
|
||||
for (std::size_t pNb = 0; pNb < metadata.parameters.size() &&
|
||||
pNb < instruction.GetParametersCount();
|
||||
++pNb) {
|
||||
const gd::String& type = metadata.parameters[pNb].type;
|
||||
const gd::String& type = metadata.parameters[pNb].GetType();
|
||||
const gd::Expression& expression = instruction.GetParameter(pNb);
|
||||
|
||||
auto node = expression.GetRootNode();
|
||||
|
@@ -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.
|
||||
|
@@ -244,6 +244,15 @@ class GD_CORE_API HighestZOrderFinder : public gd::InitialInstanceFunctor {
|
||||
*/
|
||||
size_t GetInstancesCount() const { return instancesCount; }
|
||||
|
||||
void Reset() {
|
||||
highestZOrder = 0;
|
||||
lowestZOrder = 0;
|
||||
instancesCount = 0;
|
||||
firstCall = true;
|
||||
layerRestricted = false;
|
||||
layerName.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
int highestZOrder;
|
||||
int lowestZOrder;
|
||||
|
@@ -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;
|
||||
|
@@ -28,13 +28,11 @@ class GD_EXTENSION_API DraggableBehavior : public gd::Behavior {
|
||||
return new DraggableBehavior(*this);
|
||||
}
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(
|
||||
const gd::SerializerElement& behaviorContent) const override;
|
||||
virtual bool UpdateProperty(gd::SerializerElement& behaviorContent,
|
||||
const gd::String& name,
|
||||
const gd::String& value) override;
|
||||
#endif
|
||||
|
||||
virtual void InitializeContent(
|
||||
gd::SerializerElement& behaviorContent) override;
|
||||
|
@@ -34,10 +34,9 @@ void DeclareDraggableBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
std::make_shared<DraggableBehavior>(),
|
||||
std::shared_ptr<gd::BehaviorsSharedData>());
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
aut.AddCondition("Dragged",
|
||||
_("Being dragged"),
|
||||
_("Check if the object is being dragged"),
|
||||
_("Check if the object is being dragged."),
|
||||
_("_PARAM0_ is being dragged"),
|
||||
"",
|
||||
"CppPlatform/Extensions/draggableicon24.png",
|
||||
@@ -46,5 +45,16 @@ void DeclareDraggableBehaviorExtension(gd::PlatformExtension& extension) {
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "Draggable")
|
||||
.SetFunctionName("IsDragged");
|
||||
#endif
|
||||
|
||||
aut.AddCondition("Dropped",
|
||||
_("Was just dropped"),
|
||||
_("Check if the object was just dropped after being dragged."),
|
||||
_("_PARAM0_ was just dropped"),
|
||||
"",
|
||||
"CppPlatform/Extensions/draggableicon24.png",
|
||||
"CppPlatform/Extensions/draggableicon16.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("behavior", _("Behavior"), "Draggable")
|
||||
.SetFunctionName("WasJustDropped");
|
||||
}
|
||||
|
@@ -4,7 +4,6 @@ GDevelop - Draggable Behavior Extension
|
||||
Copyright (c) 2014-2016 Florian Rival (Florian.Rival@gmail.com)
|
||||
This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
@@ -32,6 +31,11 @@ class DraggableBehaviorJsExtension : public gd::PlatformExtension {
|
||||
.SetFunctionName("isDragged")
|
||||
.SetIncludeFile(
|
||||
"Extensions/DraggableBehavior/draggableruntimebehavior.js");
|
||||
GetAllConditionsForBehavior(
|
||||
"DraggableBehavior::Draggable")["DraggableBehavior::Dropped"]
|
||||
.SetFunctionName("wasJustDropped")
|
||||
.SetIncludeFile(
|
||||
"Extensions/DraggableBehavior/draggableruntimebehavior.js");
|
||||
GD_COMPLETE_EXTENSION_COMPILATION_INFORMATION();
|
||||
};
|
||||
};
|
||||
@@ -49,4 +53,3 @@ extern "C" gd::PlatformExtension* GD_EXTENSION_API CreateGDJSExtension() {
|
||||
return new DraggableBehaviorJsExtension;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@@ -15,6 +15,7 @@ namespace gdjs {
|
||||
*/
|
||||
_draggedByDraggableManager: DraggableManager | null = null;
|
||||
_checkCollisionMask: boolean;
|
||||
_justDropped = false;
|
||||
|
||||
constructor(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
@@ -41,6 +42,7 @@ namespace gdjs {
|
||||
_endDrag() {
|
||||
if (this._draggedByDraggableManager) {
|
||||
this._draggedByDraggableManager.endDrag();
|
||||
this._justDropped = true;
|
||||
}
|
||||
this._draggedByDraggableManager = null;
|
||||
}
|
||||
@@ -126,11 +128,17 @@ namespace gdjs {
|
||||
.getGame()
|
||||
.getInputManager()
|
||||
.isMouseButtonPressed(0);
|
||||
|
||||
this._justDropped = false;
|
||||
}
|
||||
|
||||
isDragged(instanceContainer: gdjs.RuntimeInstanceContainer): boolean {
|
||||
isDragged(): boolean {
|
||||
return !!this._draggedByDraggableManager;
|
||||
}
|
||||
|
||||
wasJustDropped(): boolean {
|
||||
return this._justDropped;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -169,22 +169,20 @@ namespace gdjs {
|
||||
|
||||
// Position the input on the container on top of the canvas.
|
||||
workingPoint[0] = canvasLeft;
|
||||
workingPoint[1] = canvasRight;
|
||||
workingPoint[1] = canvasTop;
|
||||
const topLeftPageCoordinates = runtimeGameRenderer.convertCanvasToDomElementContainerCoords(
|
||||
workingPoint,
|
||||
workingPoint
|
||||
);
|
||||
const pageLeft = workingPoint[0];
|
||||
const pageTop = workingPoint[1];
|
||||
const pageLeft = topLeftPageCoordinates[0];
|
||||
const pageTop = topLeftPageCoordinates[1];
|
||||
|
||||
workingPoint[0] = canvasRight;
|
||||
workingPoint[1] = canvasBottom;
|
||||
const bottomRightPageCoordinates = runtimeGameRenderer.convertCanvasToDomElementContainerCoords(
|
||||
workingPoint,
|
||||
workingPoint
|
||||
);
|
||||
const pageRight = workingPoint[0];
|
||||
const pageBottom = workingPoint[1];
|
||||
const pageRight = bottomRightPageCoordinates[0];
|
||||
const pageBottom = bottomRightPageCoordinates[1];
|
||||
|
||||
const widthInContainer = pageRight - pageLeft;
|
||||
const heightInContainer = pageBottom - pageTop;
|
||||
|
@@ -75,8 +75,9 @@ module.exports = {
|
||||
)
|
||||
.setCategory('Visual effect')
|
||||
.setExtensionHelpPath('/behaviors/tween');
|
||||
extension.addInstructionOrExpressionGroupMetadata(_("Tweening"))
|
||||
.setIcon("JsPlatform/Extensions/tween_behavior32.png");
|
||||
extension
|
||||
.addInstructionOrExpressionGroupMetadata(_('Tweening'))
|
||||
.setIcon('JsPlatform/Extensions/tween_behavior32.png');
|
||||
|
||||
extension
|
||||
.addExpression(
|
||||
@@ -105,7 +106,7 @@ module.exports = {
|
||||
"Tweens a scene variable's numeric value from one number to another."
|
||||
),
|
||||
_(
|
||||
'Tween variable _PARAM2_ from _PARAM3_ to _PARAM4_ for _PARAM5_ms with easing _PARAM6_ as _PARAM1_'
|
||||
'Tween variable _PARAM2_ from _PARAM3_ to _PARAM4_ over _PARAM5_ms with easing _PARAM6_ as _PARAM1_'
|
||||
),
|
||||
_('Scene Tweens'),
|
||||
'JsPlatform/Extensions/tween_behavior24.png',
|
||||
@@ -118,19 +119,46 @@ module.exports = {
|
||||
.addParameter('expression', _('Final value'), '', false)
|
||||
.addParameter('expression', _('Duration'), '', false)
|
||||
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
|
||||
.setHidden()
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/shifty.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/shifty_setup.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.tweenVariableNumber');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'TweenSceneVariableNumber2',
|
||||
_('Tween a number in a scene variable'),
|
||||
_(
|
||||
"Tweens a scene variable's numeric value from its current value to a new one."
|
||||
),
|
||||
_(
|
||||
'Tween variable _PARAM2_ to _PARAM3_ over _PARAM4_ms with easing _PARAM5_ as _PARAM1_'
|
||||
),
|
||||
_('Scene Tweens'),
|
||||
'JsPlatform/Extensions/tween_behavior24.png',
|
||||
'JsPlatform/Extensions/tween_behavior32.png'
|
||||
)
|
||||
.addCodeOnlyParameter('currentScene', '')
|
||||
.addParameter('identifier', _('Tween Identifier'), 'sceneTween')
|
||||
.addParameter('scenevar', _('The variable to tween'), '', false)
|
||||
.addParameter('expression', _('Final value'), '', false)
|
||||
.addParameter('expression', _('Duration'), '', false)
|
||||
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
|
||||
.getCodeExtraInformation()
|
||||
.setIncludeFile('Extensions/TweenBehavior/shifty.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/shifty_setup.js')
|
||||
.addIncludeFile('Extensions/TweenBehavior/tweentools.js')
|
||||
.setFunctionName('gdjs.evtTools.tween.tweenVariableNumber2');
|
||||
|
||||
extension
|
||||
.addAction(
|
||||
'TweenCameraPosition',
|
||||
_('Tween the camera position'),
|
||||
_('Tweens the camera position from the current one to a new one.'),
|
||||
_(
|
||||
'Tween camera on layer _PARAM4_ to _PARAM2_;_PARAM3_ for _PARAM5_ms with easing _PARAM6_ as _PARAM1_'
|
||||
'Tween camera on layer _PARAM4_ to _PARAM2_;_PARAM3_ over _PARAM5_ms with easing _PARAM6_ as _PARAM1_'
|
||||
),
|
||||
_('Scene Tweens'),
|
||||
'JsPlatform/Extensions/tween_behavior24.png',
|
||||
@@ -155,7 +183,7 @@ module.exports = {
|
||||
_('Tween the camera zoom'),
|
||||
_('Tweens the camera zoom from the current zoom factor to a new one.'),
|
||||
_(
|
||||
'Tween the zoom of camera on layer _PARAM3_ to _PARAM2_ for _PARAM4_ms with easing _PARAM5_ as _PARAM1_'
|
||||
'Tween the zoom of camera on layer _PARAM3_ to _PARAM2_ over _PARAM4_ms with easing _PARAM5_ as _PARAM1_'
|
||||
),
|
||||
_('Scene Tweens'),
|
||||
'JsPlatform/Extensions/tween_behavior24.png',
|
||||
@@ -179,7 +207,7 @@ module.exports = {
|
||||
_('Tween the camera rotation'),
|
||||
_('Tweens the camera rotation from the current angle to a new one.'),
|
||||
_(
|
||||
'Tween the rotation of camera on layer _PARAM3_ to _PARAM2_ for _PARAM4_ms with easing _PARAM5_ as _PARAM1_'
|
||||
'Tween the rotation of camera on layer _PARAM3_ to _PARAM2_ over _PARAM4_ms with easing _PARAM5_ as _PARAM1_'
|
||||
),
|
||||
_('Scene Tweens'),
|
||||
'JsPlatform/Extensions/tween_behavior24.png',
|
||||
@@ -393,14 +421,47 @@ module.exports = {
|
||||
false
|
||||
)
|
||||
.setDefaultValue('no')
|
||||
.setHidden()
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('addVariableTween');
|
||||
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectVariableTween2',
|
||||
_('Tween a number in an object variable'),
|
||||
_(
|
||||
"Tweens an object variable's numeric value from its current value to a new one."
|
||||
),
|
||||
_(
|
||||
'Tween the variable _PARAM3_ of _PARAM0_ to _PARAM4_ with easing _PARAM5_ over _PARAM6_ms as _PARAM2_'
|
||||
),
|
||||
_('Variables'),
|
||||
'JsPlatform/Extensions/tween_behavior24.png',
|
||||
'JsPlatform/Extensions/tween_behavior32.png'
|
||||
)
|
||||
.addParameter('object', _('Object'), '', false)
|
||||
.addParameter('behavior', _('Behavior'), 'TweenBehavior', false)
|
||||
.addParameter('identifier', _('Tween Identifier'), 'objectTween')
|
||||
.addParameter('objectvar', _('Object variable'), '', false)
|
||||
.addParameter('expression', _('To value'), '', false)
|
||||
.addParameter('stringWithSelector', _('Easing'), easingChoices, false)
|
||||
.setDefaultValue('linear')
|
||||
.addParameter('expression', _('Duration, in milliseconds'), '', false)
|
||||
.addParameter(
|
||||
'yesorno',
|
||||
_('Destroy this object when tween finishes'),
|
||||
'',
|
||||
false
|
||||
)
|
||||
.setDefaultValue('no')
|
||||
.getCodeExtraInformation()
|
||||
.setFunctionName('addVariableTween2');
|
||||
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectPositionTween',
|
||||
_('Add object position tween'),
|
||||
_('Add a tween animation for the object position.'),
|
||||
_('Tween object position'),
|
||||
_('Tweens an object position from its current position to a new one.'),
|
||||
_(
|
||||
'Tween the position of _PARAM0_ to x: _PARAM3_, y: _PARAM4_ with easing _PARAM5_ over _PARAM6_ms as _PARAM2_'
|
||||
),
|
||||
@@ -429,8 +490,8 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectPositionXTween',
|
||||
_('Add object position X tween'),
|
||||
_('Add a tween animation for the object X position.'),
|
||||
_('Tween object X position'),
|
||||
_('Tweens an object X position from its current X position to a new one.'),
|
||||
_(
|
||||
'Tween the X position of _PARAM0_ to _PARAM3_ with easing _PARAM4_ over _PARAM5_ms as _PARAM2_'
|
||||
),
|
||||
@@ -458,8 +519,8 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectWidthTween',
|
||||
_('Add object width tween'),
|
||||
_('Add a tween animation for the object width.'),
|
||||
_('Tween object width'),
|
||||
_('Tweens an object width from its current width to a new one.'),
|
||||
_(
|
||||
'Tween the width of _PARAM0_ to _PARAM3_ with easing _PARAM4_ over _PARAM5_ms as _PARAM2_'
|
||||
),
|
||||
@@ -487,8 +548,8 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectHeightTween',
|
||||
_('Add object height tween'),
|
||||
_('Add a tween animation for the object height.'),
|
||||
_('Tween object height'),
|
||||
_('Tweens an object height from its current height to a new one.'),
|
||||
_(
|
||||
'Tween the height of _PARAM0_ to _PARAM3_ with easing _PARAM4_ over _PARAM5_ms as _PARAM2_'
|
||||
),
|
||||
@@ -516,8 +577,8 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectPositionYTween',
|
||||
_('Add object position Y tween'),
|
||||
_('Add a tween animation for the object Y position.'),
|
||||
_('Tween object Y position'),
|
||||
_('Tweens an object Y position from its current Y position to a new one.'),
|
||||
_(
|
||||
'Tween the Y position of _PARAM0_ to _PARAM3_ with easing _PARAM4_ over _PARAM5_ms as _PARAM2_'
|
||||
),
|
||||
@@ -545,8 +606,8 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectAngleTween',
|
||||
_('Add object angle tween'),
|
||||
_('Add a tween animation for the object angle.'),
|
||||
_('Tween object angle'),
|
||||
_('Tweens an object angle from its current angle to a new one.'),
|
||||
_(
|
||||
'Tween the angle of _PARAM0_ to _PARAM3_° with easing _PARAM4_ over _PARAM5_ms as _PARAM2_'
|
||||
),
|
||||
@@ -574,9 +635,9 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectScaleTween',
|
||||
_('Add object scale tween'),
|
||||
_('Tween object scale'),
|
||||
_(
|
||||
'Add a tween animation for the object scale (Note: the scale can never be less than 0).'
|
||||
'Tweens an object scale from its current scale to a new one (note: the scale can never be less than 0).'
|
||||
),
|
||||
_(
|
||||
'Tween the scale of _PARAM0_ to X-scale: _PARAM3_, Y-scale: _PARAM4_ (from center: _PARAM8_) with easing _PARAM5_ over _PARAM6_ms as _PARAM2_'
|
||||
@@ -608,9 +669,9 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectScaleXTween',
|
||||
_('Add object X-scale tween'),
|
||||
_('Tween object X-scale'),
|
||||
_(
|
||||
'Add a tween animation for the object X-scale (Note: the scale can never be less than 0).'
|
||||
'Tweens an object X-scale from its current value to a new one (note: the scale can never be less than 0).'
|
||||
),
|
||||
_(
|
||||
'Tween the X-scale of _PARAM0_ to _PARAM3_ (from center: _PARAM7_) with easing _PARAM4_ over _PARAM5_ms as _PARAM2_'
|
||||
@@ -641,9 +702,9 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectScaleYTween',
|
||||
_('Add object Y-scale tween'),
|
||||
_('Tween object Y-scale'),
|
||||
_(
|
||||
'Add a tween animation for the object Y-scale (Note: the scale can never be less than 0).'
|
||||
'Tweens an object Y-scale from its current value to a new one (note: the scale can never be less than 0).'
|
||||
),
|
||||
_(
|
||||
'Tween the Y-scale of _PARAM0_ to _PARAM3_ (from center: _PARAM7_) with easing _PARAM4_ over _PARAM5_ms as _PARAM2_'
|
||||
@@ -674,9 +735,9 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddTextObjectCharacterSizeTween',
|
||||
_('Add text size tween'),
|
||||
_('Tween text size'),
|
||||
_(
|
||||
'Add a tween animation for the text object character size (Note: the size can never be less than 1).'
|
||||
'Tweens the text object character size from its current value to a new one (note: the size can never be less than 1).'
|
||||
),
|
||||
_(
|
||||
'Tween the character size of _PARAM0_ to _PARAM3_ with easing _PARAM4_ over _PARAM5_ms as _PARAM2_'
|
||||
@@ -705,9 +766,9 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectOpacityTween',
|
||||
_('Add object opacity tween'),
|
||||
_('Tween object opacity'),
|
||||
_(
|
||||
'Add a tween animation for the object opacity (Value between 0 and 255).'
|
||||
'Tweens the object opacity from its current value to a new one (note: the value shall stay between 0 and 255).'
|
||||
),
|
||||
_(
|
||||
'Tween the opacity of _PARAM0_ to _PARAM3_ with easing _PARAM4_ over _PARAM5_ms as _PARAM2_'
|
||||
@@ -736,9 +797,9 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectColorTween',
|
||||
_('Add object color tween'),
|
||||
_('Tween object color'),
|
||||
_(
|
||||
'Add a tween animation for the object color. Format: "128;200;255" with values between 0 and 255 for red, green and blue'
|
||||
'Tweens the object color from its current value to a new one. Format: "128;200;255" with values between 0 and 255 for red, green and blue'
|
||||
),
|
||||
_(
|
||||
'Tween the color of _PARAM0_ to _PARAM3_ with easing _PARAM4_ over _PARAM5_ms as _PARAM2_'
|
||||
@@ -777,9 +838,9 @@ module.exports = {
|
||||
behavior
|
||||
.addAction(
|
||||
'AddObjectColorHSLTween',
|
||||
_('Add object HSL color tween'),
|
||||
_('Tween object HSL color'),
|
||||
_(
|
||||
'Add a tween animation for the object color using Hue/Saturation/Lightness. Hue can be any number, Saturation and Lightness are between 0 and 100. Use -1 for Saturation and Lightness to let them unchanged.'
|
||||
'Tweens the object color using Hue/Saturation/Lightness. Hue can be any number, Saturation and Lightness are between 0 and 100. Use -1 for Saturation and Lightness to let them unchanged.'
|
||||
),
|
||||
_(
|
||||
'Tween the color of _PARAM0_ using HSL to H: _PARAM3_ (_PARAM4_), S: _PARAM5_, L: _PARAM6_ with easing _PARAM7_ over _PARAM8_ms as _PARAM2_'
|
||||
|
@@ -206,6 +206,13 @@ namespace gdjs {
|
||||
|
||||
/**
|
||||
* Add an object variable tween.
|
||||
* @deprecated Use addVariableTween2 instead.
|
||||
* This function is misleading since one could think that the tween starts
|
||||
* right at the moment this function is called whereas the value of the variable
|
||||
* will change at the next frame only. Moreover, the variable will not start from
|
||||
* the start value exactly since time will have passed at the moment the next
|
||||
* frame is rendered.
|
||||
* See https://github.com/4ian/GDevelop/issues/4270
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param variable The object variable to store the tweened value
|
||||
* @param fromValue Start value
|
||||
@@ -240,7 +247,40 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object position tween.
|
||||
* Tween an object variable.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param variable The object variable to store the tweened value
|
||||
* @param toValue End value
|
||||
* @param easingValue Type of easing
|
||||
* @param durationValue Duration in milliseconds
|
||||
* @param destroyObjectWhenFinished Destroy this object when the tween ends
|
||||
*/
|
||||
addVariableTween2(
|
||||
identifier: string,
|
||||
variable: gdjs.Variable,
|
||||
toValue: float,
|
||||
easingValue: string,
|
||||
durationValue: float,
|
||||
destroyObjectWhenFinished: boolean
|
||||
) {
|
||||
this._addTween(
|
||||
identifier,
|
||||
easingValue,
|
||||
{
|
||||
from: { value: variable.getValue() },
|
||||
to: { value: toValue },
|
||||
duration: durationValue,
|
||||
easing: easingValue,
|
||||
render: (state) => variable.setNumber(state.value),
|
||||
},
|
||||
this._runtimeScene.getTimeManager().getTimeFromStart(),
|
||||
durationValue,
|
||||
destroyObjectWhenFinished
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tween an object position.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toX The target X position
|
||||
* @param toY The target Y position
|
||||
@@ -276,7 +316,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object X position tween.
|
||||
* Tween an object X position.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toX The target X position
|
||||
* @param easingValue Type of easing
|
||||
@@ -307,7 +347,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object Y position tween.
|
||||
* Tween an object Y position.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toY The target Y position
|
||||
* @param easingValue Type of easing
|
||||
@@ -338,7 +378,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object angle tween.
|
||||
* Tween an object angle.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toAngle The target angle
|
||||
* @param easingValue Type of easing
|
||||
@@ -371,7 +411,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object scale tween.
|
||||
* Tween an object scale.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toScaleX The target X-scale
|
||||
* @param toScaleY The target Y-scale
|
||||
@@ -429,7 +469,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object X-scale tween.
|
||||
* Tween an object X-scale.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toScaleX The target X-scale
|
||||
* @param easingValue Type of easing
|
||||
@@ -474,7 +514,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object scale y tween.
|
||||
* Tween an object Y-scale.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toScaleY The target Y-scale
|
||||
* @param easingValue Type of easing
|
||||
@@ -519,7 +559,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object opacity tween.
|
||||
* Tween an object opacity.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toOpacity The target opacity
|
||||
* @param easingValue Type of easing
|
||||
@@ -555,9 +595,9 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object color tween.
|
||||
* Tween an object color.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toColorStr The target color
|
||||
* @param toColorStr The target RGB color (format "128;200;255" with values between 0 and 255 for red, green and blue)
|
||||
* @param easingValue Type of easing
|
||||
* @param durationValue Duration in milliseconds
|
||||
* @param destroyObjectWhenFinished Destroy this object when the tween ends
|
||||
@@ -658,7 +698,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object color HSL tween, with the "to" color given using HSL (H: any number, S and L: 0-100).
|
||||
* Tween an object HSL color, with the "to" color given using HSL (H: any number, S and L: 0-100).
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toHue The target hue, or the same as the from color's hue if blank
|
||||
* @param animateHue, include hue in calculations, as can't set this to -1 as default to ignore
|
||||
@@ -738,7 +778,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a text object character size tween.
|
||||
* Tween a text object character size.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toSize The target character size
|
||||
* @param easingValue Type of easing
|
||||
@@ -774,7 +814,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object width tween.
|
||||
* Tween an object width.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toWidth The target width
|
||||
* @param easingValue Type of easing
|
||||
@@ -807,7 +847,7 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an object height tween.
|
||||
* Tween an object height.
|
||||
* @param identifier Unique id to identify the tween
|
||||
* @param toHeight The target height
|
||||
* @param easingValue Type of easing
|
||||
|
@@ -137,6 +137,15 @@ namespace gdjs {
|
||||
tween.stop().dispose();
|
||||
};
|
||||
|
||||
/**
|
||||
* @deprecated Use tweenVariableNumber2 instead.
|
||||
* This function is misleading since one could think that the tween starts
|
||||
* right at the moment this function is called whereas the value of the variable
|
||||
* will change at the next frame only. Moreover, the variable will not start from
|
||||
* the start value exactly since time will have passed at the moment the next
|
||||
* frame is rendered.
|
||||
* See https://github.com/4ian/GDevelop/issues/4270
|
||||
*/
|
||||
export const tweenVariableNumber = (
|
||||
runtimeScene: RuntimeScene,
|
||||
identifier: string,
|
||||
@@ -158,6 +167,26 @@ namespace gdjs {
|
||||
getShiftyScene(runtimeScene).add(tween);
|
||||
};
|
||||
|
||||
export const tweenVariableNumber2 = (
|
||||
runtimeScene: RuntimeScene,
|
||||
identifier: string,
|
||||
variable: Variable,
|
||||
to: number,
|
||||
duration: number,
|
||||
easing: shifty.easingFunction
|
||||
) => {
|
||||
const tween = shifty.tween({
|
||||
from: { value: variable.getValue() },
|
||||
to: { value: to },
|
||||
easing,
|
||||
duration,
|
||||
render: ({ value }) => variable.setNumber(value),
|
||||
});
|
||||
|
||||
getTweensMap(runtimeScene).set(identifier, tween);
|
||||
getShiftyScene(runtimeScene).add(tween);
|
||||
};
|
||||
|
||||
export const tweenCamera = (
|
||||
runtimeScene: RuntimeScene,
|
||||
identifier: string,
|
||||
|
@@ -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;";
|
||||
}
|
||||
|
||||
@@ -683,7 +692,7 @@ gd::String EventsCodeGenerator::GenerateFreeCondition(
|
||||
for (std::size_t i = 0; i < instrInfos.parameters.size();
|
||||
++i) // Some conditions already have a "conditionInverted" parameter
|
||||
{
|
||||
if (instrInfos.parameters[i].type == "conditionInverted")
|
||||
if (instrInfos.parameters[i].GetType() == "conditionInverted")
|
||||
conditionAlreadyTakeCareOfInversion = true;
|
||||
}
|
||||
if (!conditionAlreadyTakeCareOfInversion && conditionInverted)
|
||||
@@ -1100,17 +1109,17 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
gd::String argOutput;
|
||||
|
||||
// Code only parameter type
|
||||
if (metadata.type == "currentScene") {
|
||||
if (metadata.GetType() == "currentScene") {
|
||||
argOutput = "runtimeScene";
|
||||
}
|
||||
// Code only parameter type
|
||||
else if (metadata.type == "objectsContext") {
|
||||
else if (metadata.GetType() == "objectsContext") {
|
||||
argOutput =
|
||||
"(typeof eventsFunctionContext !== 'undefined' ? eventsFunctionContext "
|
||||
": runtimeScene)";
|
||||
}
|
||||
// Code only parameter type
|
||||
else if (metadata.type == "eventsFunctionContext") {
|
||||
else if (metadata.GetType() == "eventsFunctionContext") {
|
||||
argOutput =
|
||||
"(typeof eventsFunctionContext !== 'undefined' ? eventsFunctionContext "
|
||||
": undefined)";
|
||||
|
@@ -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,
|
||||
|
@@ -409,24 +409,20 @@ namespace gdjs {
|
||||
* Convert a point from the canvas coordinates to the dom element container coordinates.
|
||||
*
|
||||
* @param canvasCoords The point in the canvas coordinates.
|
||||
* @param result The point to return.
|
||||
* @returns The point in the dom element container coordinates.
|
||||
*/
|
||||
convertCanvasToDomElementContainerCoords(
|
||||
canvasCoords: FloatPoint,
|
||||
result: FloatPoint
|
||||
canvasCoords: FloatPoint
|
||||
): FloatPoint {
|
||||
const pageCoords = result || [0, 0];
|
||||
const pageCoords: FloatPoint = [0, 0];
|
||||
const gameResolutionWidth = this._game.getGameResolutionWidth();
|
||||
const canvasWidth = this._canvasWidth || 1;
|
||||
const gameResolutionHeight = this._game.getGameResolutionHeight();
|
||||
const canvasHeight = this._canvasHeight || 1;
|
||||
|
||||
// Handle the fact that the game is stretched to fill the canvas.
|
||||
pageCoords[0] =
|
||||
canvasCoords[0] /
|
||||
this._game.getGameResolutionWidth() /
|
||||
(this._canvasWidth || 1);
|
||||
pageCoords[1] =
|
||||
canvasCoords[1] /
|
||||
this._game.getGameResolutionHeight() /
|
||||
(this._canvasHeight || 1);
|
||||
pageCoords[0] = (canvasCoords[0] * canvasWidth) / gameResolutionWidth;
|
||||
pageCoords[1] = (canvasCoords[1] * canvasHeight) / gameResolutionHeight;
|
||||
|
||||
return pageCoords;
|
||||
}
|
||||
|
@@ -1010,6 +1010,7 @@ interface HighestZOrderFinder {
|
||||
void RestrictSearchToLayer([Const] DOMString layer);
|
||||
long GetHighestZOrder();
|
||||
long GetLowestZOrder();
|
||||
void Reset();
|
||||
unsigned long GetInstancesCount();
|
||||
};
|
||||
|
||||
@@ -1199,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();
|
||||
@@ -1210,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 {
|
||||
@@ -1245,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 {
|
||||
@@ -1261,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();
|
||||
|
||||
@@ -1271,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 {
|
||||
@@ -1316,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);
|
||||
@@ -1324,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();
|
||||
|
||||
@@ -1342,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);
|
||||
};
|
||||
@@ -2242,7 +2290,8 @@ enum EventsFunction_FunctionType {
|
||||
"EventsFunction::Action",
|
||||
"EventsFunction::Condition",
|
||||
"EventsFunction::Expression",
|
||||
"EventsFunction::StringExpression"
|
||||
"EventsFunction::ExpressionAndCondition",
|
||||
"EventsFunction::ActionWithOperator"
|
||||
};
|
||||
|
||||
interface EventsFunction {
|
||||
@@ -2259,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);
|
||||
@@ -2946,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;
|
||||
};
|
@@ -4,6 +4,7 @@ declare class gdHighestZOrderFinder extends gdInitialInstanceFunctor {
|
||||
restrictSearchToLayer(layer: string): void;
|
||||
getHighestZOrder(): number;
|
||||
getLowestZOrder(): number;
|
||||
reset(): void;
|
||||
getInstancesCount(): number;
|
||||
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>;
|
||||
|
9
newIDE/app/package-lock.json
generated
9
newIDE/app/package-lock.json
generated
@@ -30035,7 +30035,8 @@
|
||||
"node_modules/minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"devOptional": true
|
||||
},
|
||||
"node_modules/minipass": {
|
||||
"version": "3.1.3",
|
||||
@@ -46567,6 +46568,7 @@
|
||||
},
|
||||
"@lingui/react": {
|
||||
"version": "git+ssh://git@github.com/4ian/lingui-react.git#dc6b1e013470d952cf85f96cc4affdd28e29634a",
|
||||
"integrity": "sha512-eoYJ8TI+8IolPh4fue9aIwX2OVp0YrPnV86QBZLfGhxknodVeNmx+4Ic4ym7rI5/davbk9AUZHcssiH+YZWVxw==",
|
||||
"from": "@lingui/react@github:4ian/lingui-react#master",
|
||||
"requires": {
|
||||
"@lingui/core": "2.7.3",
|
||||
@@ -65573,7 +65575,8 @@
|
||||
"minimist": {
|
||||
"version": "1.2.5",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
||||
"devOptional": true
|
||||
},
|
||||
"minipass": {
|
||||
"version": "3.1.3",
|
||||
@@ -66891,6 +66894,7 @@
|
||||
},
|
||||
"pixi-simple-gesture": {
|
||||
"version": "git+ssh://git@github.com/4ian/pixi-simple-gesture.git#c84e0cc3c62edeca019e708d9897ef6b97a0d18a",
|
||||
"integrity": "sha512-DG1BxP8SK2iPMYWMOPGz5gKDXFmA8JPUpcyyNyIH55fpQraenuLYlosYFFMTRXEy0RZViTUu11H3VrYlfG2CgA==",
|
||||
"from": "pixi-simple-gesture@github:4ian/pixi-simple-gesture#v0.3.3"
|
||||
},
|
||||
"pixi.js": {
|
||||
@@ -69300,6 +69304,7 @@
|
||||
},
|
||||
"react-mosaic-component": {
|
||||
"version": "git+ssh://git@github.com/4ian/react-mosaic.git#d5ef155119d786c08c7c72e34997dcef2f01f98b",
|
||||
"integrity": "sha512-Izfw/EkG1g39nrZbOqzY52rqFkVFA1SUSv1TLwk7soS1Wy7iHm6zrUgzJdfwKRC2GaDn9WAfSe5ZQ2vIJ/mu5A==",
|
||||
"from": "react-mosaic-component@github:4ian/react-mosaic#v3.1.0",
|
||||
"requires": {
|
||||
"classnames": "^2.2.6",
|
||||
|
@@ -206,23 +206,23 @@ const commandsList: { [CommandName]: CommandMetadata } = {
|
||||
// Scene editor toolbar commands
|
||||
OPEN_OBJECTS_PANEL: {
|
||||
area: 'SCENE',
|
||||
displayText: t`Open the objects editor`,
|
||||
displayText: t`Open Objects Panel`,
|
||||
},
|
||||
OPEN_OBJECT_GROUPS_PANEL: {
|
||||
area: 'SCENE',
|
||||
displayText: t`Open the object groups editor`,
|
||||
displayText: t`Open Object Groups Panel`,
|
||||
},
|
||||
OPEN_PROPERTIES_PANEL: {
|
||||
area: 'SCENE',
|
||||
displayText: t`Open the properties panel`,
|
||||
displayText: t`Open Properties Panel`,
|
||||
},
|
||||
TOGGLE_INSTANCES_PANEL: {
|
||||
area: 'SCENE',
|
||||
displayText: t`Open the list of instances`,
|
||||
displayText: t`Open Instances List Panel`,
|
||||
},
|
||||
TOGGLE_LAYERS_PANEL: {
|
||||
area: 'SCENE',
|
||||
displayText: t`Open the layers editor`,
|
||||
displayText: t`Open Layers Panel`,
|
||||
},
|
||||
SCENE_EDITOR_UNDO: {
|
||||
area: 'SCENE',
|
||||
|
@@ -45,6 +45,8 @@ import { ResponsiveLineStackLayout } from '../UI/Layout';
|
||||
import Text from '../UI/Text';
|
||||
import GDevelopThemeContext from '../UI/Theme/ThemeContext';
|
||||
|
||||
const DragSourceAndDropTarget = makeDragSourceAndDropTarget('effects-list');
|
||||
|
||||
const styles = {
|
||||
rowContainer: {
|
||||
display: 'flex',
|
||||
@@ -94,10 +96,6 @@ export default function EffectsList(props: Props) {
|
||||
const [nameErrors, setNameErrors] = React.useState<{ [number]: React.Node }>(
|
||||
{}
|
||||
);
|
||||
const DragSourceAndDropTarget = React.useMemo(
|
||||
() => makeDragSourceAndDropTarget('effects-list'),
|
||||
[]
|
||||
);
|
||||
|
||||
const allEffectMetadata = React.useMemo(
|
||||
() => enumerateEffectsMetadata(props.project),
|
||||
|
@@ -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(
|
||||
@@ -536,8 +737,9 @@ export const declareBehaviorPropertiesInstructionAndExpressions = (
|
||||
const setterName = gd.BehaviorCodeGenerator.getBehaviorPropertySetterName(
|
||||
propertyName
|
||||
);
|
||||
const propertyLabel =
|
||||
property.getLabel() || i18n._(t`${propertyName} property`);
|
||||
const propertyLabel = i18n._(
|
||||
t`${property.getLabel() || propertyName} property`
|
||||
);
|
||||
|
||||
if (propertyType === 'String' || propertyType === 'Choice') {
|
||||
addObjectAndBehaviorParameters(
|
||||
@@ -660,7 +862,7 @@ export const declareBehaviorPropertiesInstructionAndExpressions = (
|
||||
behaviorMetadata.addScopedCondition(
|
||||
gd.EventsBasedBehavior.getPropertyConditionName(propertyName),
|
||||
propertyLabel,
|
||||
i18n._(t`Check the color ${propertyLabel}`),
|
||||
i18n._(t`Check the color of ${propertyLabel}`),
|
||||
i18n._(t`Color ${propertyName}`),
|
||||
eventsBasedBehavior.getFullName() || eventsBasedBehavior.getName(),
|
||||
getExtensionIconUrl(extension),
|
||||
@@ -740,8 +942,9 @@ export const declareObjectPropertiesInstructionAndExpressions = (
|
||||
const setterName = gd.ObjectCodeGenerator.getObjectPropertySetterName(
|
||||
propertyName
|
||||
);
|
||||
const propertyLabel =
|
||||
property.getLabel() || i18n._(t`${propertyName} property`);
|
||||
const propertyLabel = i18n._(
|
||||
t`${property.getLabel() || propertyName} property`
|
||||
);
|
||||
|
||||
if (propertyType === 'String' || propertyType === 'Choice') {
|
||||
addObjectParameter(
|
||||
@@ -864,7 +1067,7 @@ export const declareObjectPropertiesInstructionAndExpressions = (
|
||||
objectMetadata.addScopedCondition(
|
||||
gd.EventsBasedObject.getPropertyConditionName(propertyName),
|
||||
propertyLabel,
|
||||
i18n._(t`Check the color ${propertyLabel}`),
|
||||
i18n._(t`Check the color of ${propertyLabel}`),
|
||||
i18n._(t`Color ${propertyName}`),
|
||||
eventsBasedObject.getFullName() || eventsBasedObject.getName(),
|
||||
getExtensionIconUrl(extension),
|
||||
@@ -910,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();
|
||||
|
@@ -1,3 +1,5 @@
|
||||
// @flow
|
||||
import { type ComponentType } from 'react';
|
||||
import UnknownEvent from './Renderers/UnknownEvent';
|
||||
import StandardEvent from './Renderers/StandardEvent';
|
||||
import GroupEvent from './Renderers/GroupEvent';
|
||||
@@ -8,6 +10,7 @@ import RepeatEvent from './Renderers/RepeatEvent';
|
||||
import WhileEvent from './Renderers/WhileEvent';
|
||||
import LinkEvent from './Renderers/LinkEvent';
|
||||
import JsCodeEvent from './Renderers/JsCodeEvent';
|
||||
import { type EventRendererProps } from './Renderers/EventRenderer';
|
||||
|
||||
const EventsRenderingService = {
|
||||
components: {
|
||||
@@ -22,12 +25,17 @@ const EventsRenderingService = {
|
||||
'BuiltinCommonInstructions::Link': LinkEvent,
|
||||
'BuiltinCommonInstructions::JsCode': JsCodeEvent,
|
||||
},
|
||||
getEventComponent: function(event) {
|
||||
getEventComponent: function(
|
||||
event: gdBaseEvent
|
||||
): ComponentType<EventRendererProps> {
|
||||
if (this.components.hasOwnProperty(event.getType()))
|
||||
return this.components[event.getType()];
|
||||
else return this.components.unknownEvent;
|
||||
},
|
||||
registerEvent: function(eventType, renderFunction) {
|
||||
registerEvent: function(
|
||||
eventType: string,
|
||||
renderFunction: ComponentType<EventRendererProps>
|
||||
) {
|
||||
if (!this.components.hasOwnProperty(eventType)) {
|
||||
console.warn(
|
||||
'Tried to register renderer for events "' +
|
||||
|
@@ -120,6 +120,7 @@ type EventsContainerProps = {|
|
||||
eventsSheetHeight: number,
|
||||
|
||||
connectDragSource: ConnectDragSource,
|
||||
windowWidth: WidthType,
|
||||
|};
|
||||
|
||||
/**
|
||||
@@ -158,7 +159,7 @@ class EventContainer extends Component<EventsContainerProps, {||}> {
|
||||
onClick={this.props.onEventClick}
|
||||
onContextMenu={this._onEventContextMenu}
|
||||
>
|
||||
{EventComponent && (
|
||||
{!!EventComponent && (
|
||||
<div style={styles.eventComponentContainer}>
|
||||
{this.props.connectDragSource(<div className={handle} />)}
|
||||
<div style={styles.container}>
|
||||
@@ -192,6 +193,7 @@ class EventContainer extends Component<EventsContainerProps, {||}> {
|
||||
renderObjectThumbnail={this.props.renderObjectThumbnail}
|
||||
screenType={this.props.screenType}
|
||||
eventsSheetHeight={this.props.eventsSheetHeight}
|
||||
windowWidth={this.props.windowWidth}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -781,6 +783,7 @@ export default class ThemableEventsTree extends Component<
|
||||
screenType={this.props.screenType}
|
||||
eventsSheetHeight={this.props.eventsSheetHeight}
|
||||
connectDragSource={connectDragSource}
|
||||
windowWidth={this.props.windowWidth}
|
||||
/>
|
||||
{this.state.draggedNode && (
|
||||
<DropContainer
|
||||
|
@@ -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
|
||||
|
@@ -14,6 +14,7 @@ import { type ParameterRenderingServiceType } from '../ParameterFieldCommons';
|
||||
import { type EnumeratedInstructionOrExpressionMetadata } from '../../../InstructionOrExpression/EnumeratedInstructionOrExpressionMetadata';
|
||||
import { Column, Line, Spacer } from '../../../UI/Grid';
|
||||
import ObjectsRenderingService from '../../../ObjectsRendering/ObjectsRenderingService';
|
||||
import GDevelopThemeContext from '../../../UI/Theme/ThemeContext';
|
||||
|
||||
const defaultTextStyle = {
|
||||
// Break words if they are too long to fit on a single line.
|
||||
@@ -273,6 +274,7 @@ export default function ExpressionAutocompletionsDisplayer({
|
||||
onScroll,
|
||||
parameterRenderingService,
|
||||
}: Props) {
|
||||
const gdevelopTheme = React.useContext(GDevelopThemeContext);
|
||||
const scrollView = React.useRef((null: ?ScrollViewInterface));
|
||||
const selectedAutocompletionElement = React.useRef(
|
||||
(null: ?React$Component<any, any>)
|
||||
@@ -303,7 +305,14 @@ export default function ExpressionAutocompletionsDisplayer({
|
||||
false
|
||||
}
|
||||
>
|
||||
<Paper variant="outlined" square style={styles.container}>
|
||||
<Paper
|
||||
variant="outlined"
|
||||
square
|
||||
style={{
|
||||
...styles.container,
|
||||
backgroundColor: gdevelopTheme.palette.alternateCanvasColor,
|
||||
}}
|
||||
>
|
||||
<ScrollView ref={scrollView} onScroll={onScroll}>
|
||||
{expressionAutocompletions.map(
|
||||
(expressionAutocompletion, index) => {
|
||||
@@ -365,7 +374,14 @@ export default function ExpressionAutocompletionsDisplayer({
|
||||
expressionAutocompletions[selectedCompletionIndex].kind ===
|
||||
'Expression' &&
|
||||
!expressionAutocompletions[selectedCompletionIndex].isExact && (
|
||||
<Paper variant="outlined" square style={styles.container}>
|
||||
<Paper
|
||||
variant="outlined"
|
||||
square
|
||||
style={{
|
||||
...styles.container,
|
||||
backgroundColor: gdevelopTheme.palette.alternateCanvasColor,
|
||||
}}
|
||||
>
|
||||
<ScrollView autoHideScrollbar>
|
||||
<Column>
|
||||
<Line noMargin expand alignItems="center">
|
||||
|
@@ -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()}"`);
|
||||
}
|
||||
|
@@ -67,6 +67,7 @@ import LeaderboardSortOptionsDialog from './LeaderboardSortOptionsDialog';
|
||||
import { type LeaderboardSortOption } from '../../Utils/GDevelopServices/Play';
|
||||
import { formatScore } from '../../Leaderboard/LeaderboardScoreFormatter';
|
||||
import Toggle from '../../UI/Toggle';
|
||||
import GDevelopThemeContext from '../../UI/Theme/ThemeContext';
|
||||
|
||||
type Props = {|
|
||||
onLoading: boolean => void,
|
||||
@@ -183,6 +184,7 @@ export const LeaderboardAdmin = ({
|
||||
leaderboardIdToSelectAtOpening,
|
||||
}: Props) => {
|
||||
const isOnline = useOnlineStatus();
|
||||
const gdevelopTheme = React.useContext(GDevelopThemeContext);
|
||||
const windowWidth = useResponsiveWindowWidth();
|
||||
const [isEditingAppearance, setIsEditingAppearance] = React.useState<boolean>(
|
||||
false
|
||||
@@ -839,7 +841,13 @@ export const LeaderboardAdmin = ({
|
||||
<>
|
||||
<ResponsiveLineStackLayout noMargin expand noColumnMargin>
|
||||
<div style={styles.leftColumn}>
|
||||
<Paper elevation={5} style={styles.leaderboardConfigurationPaper}>
|
||||
<Paper
|
||||
elevation={5}
|
||||
style={{
|
||||
...styles.leaderboardConfigurationPaper,
|
||||
backgroundColor: gdevelopTheme.palette.alternateCanvasColor,
|
||||
}}
|
||||
>
|
||||
<Column>
|
||||
<Line>
|
||||
{currentLeaderboard && leaderboards ? (
|
||||
|
@@ -1,9 +1,8 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { I18n } from '@lingui/react';
|
||||
import { type I18n as I18nType } from '@lingui/core';
|
||||
import { t } from '@lingui/macro';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import React from 'react';
|
||||
import { t, Trans } from '@lingui/macro';
|
||||
import { TreeTableRow, TreeTableCell } from '../UI/TreeTable';
|
||||
import InlineCheckbox from '../UI/InlineCheckbox';
|
||||
import Visibility from '@material-ui/icons/Visibility';
|
||||
@@ -11,21 +10,32 @@ import VisibilityOff from '@material-ui/icons/VisibilityOff';
|
||||
import FlareIcon from '@material-ui/icons/Flare';
|
||||
import IconButton from '../UI/IconButton';
|
||||
import Delete from '@material-ui/icons/Delete';
|
||||
import TextField from '../UI/TextField';
|
||||
import SemiControlledTextField from '../UI/SemiControlledTextField';
|
||||
import DragHandle from '../UI/DragHandle';
|
||||
import ElementWithMenu from '../UI/Menu/ElementWithMenu';
|
||||
import MoreVert from '@material-ui/icons/MoreVert';
|
||||
import EmojiObjectsIcon from '@material-ui/icons/EmojiObjects';
|
||||
import EditIcon from '@material-ui/icons/Edit';
|
||||
import Badge from '../UI/Badge';
|
||||
import { makeDragSourceAndDropTarget } from '../UI/DragAndDrop/DragSourceAndDropTarget';
|
||||
import GDevelopThemeContext from '../UI/Theme/ThemeContext';
|
||||
|
||||
const DragSourceAndDropTarget = makeDragSourceAndDropTarget('layers-list');
|
||||
|
||||
export const styles = {
|
||||
dropIndicator: {
|
||||
outline: '1px solid white',
|
||||
},
|
||||
};
|
||||
|
||||
type Props = {|
|
||||
layerName: string,
|
||||
nameError: boolean,
|
||||
onBlur: () => void,
|
||||
layer: gdLayer,
|
||||
nameError: React.Node,
|
||||
onBlur: string => void,
|
||||
onRemove: () => void,
|
||||
onBeginDrag: () => void,
|
||||
onDrop: () => void,
|
||||
isVisible: boolean,
|
||||
isLightingLayer: boolean,
|
||||
onChangeVisibility: boolean => void,
|
||||
effectsCount: number,
|
||||
onEditEffects: () => void,
|
||||
@@ -34,7 +44,7 @@ type Props = {|
|
||||
|};
|
||||
|
||||
const LayerRow = ({
|
||||
layerName,
|
||||
layer,
|
||||
nameError,
|
||||
onBlur,
|
||||
onRemove,
|
||||
@@ -42,111 +52,153 @@ const LayerRow = ({
|
||||
effectsCount,
|
||||
onEditEffects,
|
||||
onChangeVisibility,
|
||||
onBeginDrag,
|
||||
onDrop,
|
||||
width,
|
||||
isLightingLayer,
|
||||
onEdit,
|
||||
}: Props) => (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<TreeTableRow>
|
||||
<TreeTableCell>
|
||||
<DragHandle />
|
||||
</TreeTableCell>
|
||||
<TreeTableCell expand>
|
||||
<TextField
|
||||
margin="none"
|
||||
defaultValue={layerName || i18n._(t`Base layer`)}
|
||||
id={layerName}
|
||||
errorText={
|
||||
nameError ? <Trans>This name is already taken</Trans> : undefined
|
||||
}
|
||||
disabled={!layerName}
|
||||
onBlur={onBlur}
|
||||
fullWidth
|
||||
/>
|
||||
</TreeTableCell>
|
||||
<TreeTableCell>
|
||||
{width < 350 ? (
|
||||
<ElementWithMenu
|
||||
element={
|
||||
<IconButton size="small">
|
||||
<MoreVert />
|
||||
</IconButton>
|
||||
}
|
||||
buildMenuTemplate={(i18n: I18nType) => [
|
||||
{
|
||||
label: isLightingLayer
|
||||
? i18n._(t`Edit lighting properties`)
|
||||
: i18n._(t`Edit properties`),
|
||||
click: onEdit,
|
||||
},
|
||||
{
|
||||
label: i18n._(t`Edit effects (${effectsCount})`),
|
||||
click: onEditEffects,
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: i18n._(t`Visible`),
|
||||
checked: isVisible,
|
||||
click: () => onChangeVisibility(!isVisible),
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: i18n._(t`Delete`),
|
||||
enabled: !!layerName,
|
||||
click: onRemove,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<InlineCheckbox
|
||||
checked={isVisible}
|
||||
checkedIcon={<Visibility />}
|
||||
uncheckedIcon={<VisibilityOff />}
|
||||
onCheck={(e, value) => onChangeVisibility(value)}
|
||||
tooltipOrHelperText={
|
||||
isVisible ? (
|
||||
<Trans>Hide layer</Trans>
|
||||
) : (
|
||||
<Trans>Show layer</Trans>
|
||||
)
|
||||
}
|
||||
/>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={onEditEffects}
|
||||
tooltip={t`Edit effects (${effectsCount})`}
|
||||
>
|
||||
<Badge badgeContent={effectsCount} color="primary">
|
||||
<FlareIcon />
|
||||
</Badge>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={onEdit}
|
||||
tooltip={
|
||||
isLightingLayer
|
||||
? t`Edit lighting properties`
|
||||
: t`Edit properties`
|
||||
}
|
||||
>
|
||||
{isLightingLayer ? <EmojiObjectsIcon /> : <EditIcon />}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={onRemove}
|
||||
disabled={!layerName}
|
||||
tooltip={t`Delete the layer`}
|
||||
>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</TreeTableCell>
|
||||
</TreeTableRow>
|
||||
)}
|
||||
</I18n>
|
||||
);
|
||||
}: Props) => {
|
||||
const gdevelopTheme = React.useContext(GDevelopThemeContext);
|
||||
|
||||
const layerName = layer.getName();
|
||||
const isLightingLayer = layer.isLightingLayer();
|
||||
|
||||
const isBaseLayer = !layerName;
|
||||
|
||||
return (
|
||||
<I18n>
|
||||
{({ i18n }) => (
|
||||
<DragSourceAndDropTarget
|
||||
key={layer.ptr}
|
||||
beginDrag={() => {
|
||||
onBeginDrag();
|
||||
return {};
|
||||
}}
|
||||
canDrag={() => true}
|
||||
canDrop={() => true}
|
||||
drop={onDrop}
|
||||
>
|
||||
{({ connectDragSource, connectDropTarget, isOver, canDrop }) =>
|
||||
connectDropTarget(
|
||||
<div>
|
||||
{isOver && (
|
||||
<div
|
||||
style={{
|
||||
...styles.dropIndicator,
|
||||
outlineColor: gdevelopTheme.dropIndicator.canDrop,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<TreeTableRow>
|
||||
<TreeTableCell>
|
||||
{connectDragSource(
|
||||
<span>
|
||||
<DragHandle />
|
||||
</span>
|
||||
)}
|
||||
</TreeTableCell>
|
||||
<TreeTableCell expand>
|
||||
<SemiControlledTextField
|
||||
margin="none"
|
||||
value={isBaseLayer ? i18n._(t`Base layer`) : layerName}
|
||||
id={layerName}
|
||||
errorText={nameError}
|
||||
disabled={isBaseLayer}
|
||||
onChange={onBlur}
|
||||
commitOnBlur
|
||||
fullWidth
|
||||
/>
|
||||
</TreeTableCell>
|
||||
<TreeTableCell>
|
||||
{width < 350 ? (
|
||||
<ElementWithMenu
|
||||
element={
|
||||
<IconButton size="small">
|
||||
<MoreVert />
|
||||
</IconButton>
|
||||
}
|
||||
buildMenuTemplate={(i18n: I18nType) => [
|
||||
{
|
||||
label: isLightingLayer
|
||||
? i18n._(t`Edit lighting properties`)
|
||||
: i18n._(t`Edit properties`),
|
||||
click: onEdit,
|
||||
},
|
||||
{
|
||||
label: i18n._(t`Edit effects (${effectsCount})`),
|
||||
click: onEditEffects,
|
||||
},
|
||||
{
|
||||
type: 'checkbox',
|
||||
label: i18n._(t`Visible`),
|
||||
checked: isVisible,
|
||||
click: () => onChangeVisibility(!isVisible),
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: i18n._(t`Delete`),
|
||||
enabled: !isBaseLayer,
|
||||
click: onRemove,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
) : (
|
||||
<React.Fragment>
|
||||
<InlineCheckbox
|
||||
checked={isVisible}
|
||||
checkedIcon={<Visibility />}
|
||||
uncheckedIcon={<VisibilityOff />}
|
||||
onCheck={(e, value) => onChangeVisibility(value)}
|
||||
tooltipOrHelperText={
|
||||
isVisible ? (
|
||||
<Trans>Hide layer</Trans>
|
||||
) : (
|
||||
<Trans>Show layer</Trans>
|
||||
)
|
||||
}
|
||||
/>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={onEditEffects}
|
||||
tooltip={t`Edit effects (${effectsCount})`}
|
||||
>
|
||||
<Badge badgeContent={effectsCount} color="primary">
|
||||
<FlareIcon />
|
||||
</Badge>
|
||||
</IconButton>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={onEdit}
|
||||
tooltip={
|
||||
isLightingLayer
|
||||
? t`Edit lighting properties`
|
||||
: t`Edit properties`
|
||||
}
|
||||
>
|
||||
{isLightingLayer ? (
|
||||
<EmojiObjectsIcon />
|
||||
) : (
|
||||
<EditIcon />
|
||||
)}
|
||||
</IconButton>
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={onRemove}
|
||||
disabled={isBaseLayer}
|
||||
tooltip={t`Delete the layer`}
|
||||
>
|
||||
<Delete />
|
||||
</IconButton>
|
||||
</React.Fragment>
|
||||
)}
|
||||
</TreeTableCell>
|
||||
</TreeTableRow>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</DragSourceAndDropTarget>
|
||||
)}
|
||||
</I18n>
|
||||
);
|
||||
};
|
||||
|
||||
export default LayerRow;
|
||||
|
@@ -1,10 +1,9 @@
|
||||
// @flow
|
||||
import { t, Trans } from '@lingui/macro';
|
||||
import React, { Component } from 'react';
|
||||
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
|
||||
import * as React from 'react';
|
||||
import newNameGenerator from '../Utils/NewNameGenerator';
|
||||
import { mapReverseFor } from '../Utils/MapFor';
|
||||
import LayerRow from './LayerRow';
|
||||
import LayerRow, { styles } from './LayerRow';
|
||||
import BackgroundColorRow from './BackgroundColorRow';
|
||||
import { Column, Line } from '../UI/Grid';
|
||||
import Add from '@material-ui/icons/Add';
|
||||
@@ -20,96 +19,149 @@ import Background from '../UI/Background';
|
||||
import { type HotReloadPreviewButtonProps } from '../HotReload/HotReloadPreviewButton';
|
||||
import RaisedButtonWithSplitMenu from '../UI/RaisedButtonWithSplitMenu';
|
||||
import useForceUpdate from '../Utils/UseForceUpdate';
|
||||
import { makeDropTarget } from '../UI/DragAndDrop/DropTarget';
|
||||
import GDevelopThemeContext from '../UI/Theme/ThemeContext';
|
||||
|
||||
const SortableLayerRow = SortableElement(LayerRow);
|
||||
const DropTarget = makeDropTarget('layers-list');
|
||||
|
||||
type LayersListBodyState = {|
|
||||
nameErrors: { [string]: boolean },
|
||||
type LayersListBodyProps = {|
|
||||
layersContainer: gdLayout,
|
||||
unsavedChanges?: ?UnsavedChanges,
|
||||
onRemoveLayer: (layerName: string, cb: (done: boolean) => void) => void,
|
||||
onRenameLayer: (
|
||||
oldName: string,
|
||||
newName: string,
|
||||
cb: (done: boolean) => void
|
||||
) => void,
|
||||
onEditEffects: (layer: ?gdLayer) => void,
|
||||
onEdit: (layer: ?gdLayer) => void,
|
||||
width: number,
|
||||
|};
|
||||
|
||||
class LayersListBody extends Component<*, LayersListBodyState> {
|
||||
state = {
|
||||
nameErrors: {},
|
||||
const LayersListBody = (props: LayersListBodyProps) => {
|
||||
const forceUpdate = useForceUpdate();
|
||||
const gdevelopTheme = React.useContext(GDevelopThemeContext);
|
||||
const [nameErrors, setNameErrors] = React.useState<{
|
||||
[key: string]: React.Node,
|
||||
}>({});
|
||||
const draggedLayerIndexRef = React.useRef<number | null>(null);
|
||||
|
||||
const {
|
||||
layersContainer,
|
||||
onEditEffects,
|
||||
onEdit,
|
||||
width,
|
||||
onRenameLayer,
|
||||
onRemoveLayer,
|
||||
unsavedChanges,
|
||||
} = props;
|
||||
|
||||
const onLayerModified = () => {
|
||||
if (unsavedChanges) unsavedChanges.triggerUnsavedChanges();
|
||||
forceUpdate();
|
||||
};
|
||||
|
||||
_onLayerModified = () => {
|
||||
if (this.props.unsavedChanges)
|
||||
this.props.unsavedChanges.triggerUnsavedChanges();
|
||||
this.forceUpdate();
|
||||
};
|
||||
const onDropLayer = (targetIndex: number) => {
|
||||
const { current: draggedLayerIndex } = draggedLayerIndexRef;
|
||||
if (draggedLayerIndex === null) return;
|
||||
|
||||
render() {
|
||||
const { layersContainer, onEditEffects, onEdit, width } = this.props;
|
||||
|
||||
const layersCount = layersContainer.getLayersCount();
|
||||
const containerLayersList = mapReverseFor(0, layersCount, i => {
|
||||
const layer = layersContainer.getLayerAt(i);
|
||||
const layerName = layer.getName();
|
||||
const isLightingLayer = layer.isLightingLayer();
|
||||
|
||||
return (
|
||||
<SortableLayerRow
|
||||
index={layersCount - 1 - i}
|
||||
key={'layer-' + layerName}
|
||||
layer={layer}
|
||||
layerName={layerName}
|
||||
isLightingLayer={isLightingLayer}
|
||||
nameError={this.state.nameErrors[layerName]}
|
||||
effectsCount={layer.getEffects().getEffectsCount()}
|
||||
onEditEffects={() => onEditEffects(layer)}
|
||||
onEdit={() => onEdit(layer)}
|
||||
onBlur={event => {
|
||||
const newName = event.target.value;
|
||||
if (layerName === newName) return;
|
||||
|
||||
let success = true;
|
||||
if (layersContainer.hasLayerNamed(newName)) {
|
||||
success = false;
|
||||
} else {
|
||||
this.props.onRenameLayer(layerName, newName, doRename => {
|
||||
if (doRename)
|
||||
layersContainer.getLayer(layerName).setName(newName);
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({
|
||||
nameErrors: {
|
||||
...this.state.nameErrors,
|
||||
[layerName]: !success,
|
||||
},
|
||||
});
|
||||
}}
|
||||
onRemove={() => {
|
||||
this.props.onRemoveLayer(layerName, doRemove => {
|
||||
if (!doRemove) return;
|
||||
|
||||
layersContainer.removeLayer(layerName);
|
||||
this._onLayerModified();
|
||||
});
|
||||
}}
|
||||
isVisible={layer.getVisibility()}
|
||||
onChangeVisibility={visible => {
|
||||
layer.setVisibility(visible);
|
||||
this._onLayerModified();
|
||||
}}
|
||||
width={width}
|
||||
/>
|
||||
if (targetIndex !== draggedLayerIndex) {
|
||||
layersContainer.moveLayer(
|
||||
draggedLayerIndex,
|
||||
targetIndex < draggedLayerIndex ? targetIndex + 1 : targetIndex
|
||||
);
|
||||
});
|
||||
onLayerModified();
|
||||
}
|
||||
draggedLayerIndexRef.current = null;
|
||||
};
|
||||
|
||||
const layersCount = layersContainer.getLayersCount();
|
||||
const containerLayersList = mapReverseFor(0, layersCount, i => {
|
||||
const layer = layersContainer.getLayerAt(i);
|
||||
const layerName = layer.getName();
|
||||
|
||||
return (
|
||||
<Column noMargin expand>
|
||||
{containerLayersList}
|
||||
<BackgroundColorRow
|
||||
layout={layersContainer}
|
||||
onBackgroundColorChanged={() => this._onLayerModified()}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
}
|
||||
<LayerRow
|
||||
key={'layer-' + layer.ptr}
|
||||
layer={layer}
|
||||
nameError={nameErrors[layerName]}
|
||||
effectsCount={layer.getEffects().getEffectsCount()}
|
||||
onEditEffects={() => onEditEffects(layer)}
|
||||
onEdit={() => onEdit(layer)}
|
||||
onBeginDrag={() => {
|
||||
draggedLayerIndexRef.current = i;
|
||||
}}
|
||||
onDrop={() => onDropLayer(i)}
|
||||
onBlur={newName => {
|
||||
setNameErrors(currentValue => ({
|
||||
...currentValue,
|
||||
[layerName]: null,
|
||||
}));
|
||||
|
||||
const SortableLayersListBody = SortableContainer(LayersListBody);
|
||||
if (layerName === newName) return;
|
||||
|
||||
const isNameAlreadyTaken = layersContainer.hasLayerNamed(newName);
|
||||
if (isNameAlreadyTaken) {
|
||||
setNameErrors(currentValue => ({
|
||||
...currentValue,
|
||||
[layerName]: <Trans>The name {newName} is already taken</Trans>,
|
||||
}));
|
||||
} else {
|
||||
onRenameLayer(layerName, newName, doRename => {
|
||||
if (doRename)
|
||||
layersContainer.getLayer(layerName).setName(newName);
|
||||
});
|
||||
}
|
||||
}}
|
||||
onRemove={() => {
|
||||
onRemoveLayer(layerName, doRemove => {
|
||||
if (!doRemove) return;
|
||||
|
||||
layersContainer.removeLayer(layerName);
|
||||
onLayerModified();
|
||||
});
|
||||
}}
|
||||
isVisible={layer.getVisibility()}
|
||||
onChangeVisibility={visible => {
|
||||
layer.setVisibility(visible);
|
||||
onLayerModified();
|
||||
}}
|
||||
width={width}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<Column noMargin expand>
|
||||
{containerLayersList}
|
||||
<DropTarget
|
||||
canDrop={() => true}
|
||||
drop={() => {
|
||||
onDropLayer(-1);
|
||||
}}
|
||||
>
|
||||
{({ connectDropTarget, isOver, canDrop }) =>
|
||||
connectDropTarget(
|
||||
<div>
|
||||
{isOver && (
|
||||
<div
|
||||
style={{
|
||||
...styles.dropIndicator,
|
||||
outlineColor: gdevelopTheme.dropIndicator.canDrop,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<BackgroundColorRow
|
||||
layout={layersContainer}
|
||||
onBackgroundColorChanged={onLayerModified}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</DropTarget>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
||||
type Props = {|
|
||||
project: gdProject,
|
||||
@@ -195,23 +247,13 @@ const LayersList = React.forwardRef<Props, LayersListInterface>(
|
||||
{({ width }) => (
|
||||
// TODO: The list is costly to render when there are many layers, consider
|
||||
// using SortableVirtualizedItemList.
|
||||
<SortableLayersListBody
|
||||
<LayersListBody
|
||||
key={listKey}
|
||||
layersContainer={props.layersContainer}
|
||||
onEditEffects={props.onEditLayerEffects}
|
||||
onEdit={props.onEditLayer}
|
||||
onRemoveLayer={props.onRemoveLayer}
|
||||
onRenameLayer={props.onRenameLayer}
|
||||
onSortEnd={({ oldIndex, newIndex }) => {
|
||||
const layersCount = props.layersContainer.getLayersCount();
|
||||
props.layersContainer.moveLayer(
|
||||
layersCount - 1 - oldIndex,
|
||||
layersCount - 1 - newIndex
|
||||
);
|
||||
onLayerModified();
|
||||
}}
|
||||
helperClass="sortable-helper"
|
||||
useDragHandle
|
||||
unsavedChanges={props.unsavedChanges}
|
||||
width={width}
|
||||
/>
|
||||
|
@@ -16,6 +16,10 @@ import {
|
||||
type ClosableTabProps,
|
||||
} from '../../UI/ClosableTabs';
|
||||
|
||||
const DragSourceAndDropTarget = makeDragSourceAndDropTarget<EditorTab>(
|
||||
'draggable-closable-tab'
|
||||
);
|
||||
|
||||
type DraggableEditorTabsProps = {|
|
||||
hideLabels?: boolean,
|
||||
editorTabs: EditorTabsState,
|
||||
@@ -96,10 +100,6 @@ export function DraggableClosableTab({
|
||||
onBeginDrag,
|
||||
onDrop,
|
||||
}: DraggableClosableTabProps) {
|
||||
const DragSourceAndDropTarget = makeDragSourceAndDropTarget<EditorTab>(
|
||||
'draggable-closable-tab'
|
||||
);
|
||||
|
||||
return (
|
||||
<ScreenTypeMeasurer>
|
||||
{screenType => (
|
||||
|
@@ -289,7 +289,7 @@ export const initialPreferences = {
|
||||
eventsSheetShowObjectThumbnails: true,
|
||||
autosaveOnPreview: true,
|
||||
useNewInstructionEditorDialog: true,
|
||||
useUndefinedVariablesInAutocompletion: false,
|
||||
useUndefinedVariablesInAutocompletion: true,
|
||||
useGDJSDevelopmentWatcher: true,
|
||||
eventsSheetUseAssignmentOperators: false,
|
||||
eventsSheetZoomLevel: 14,
|
||||
|
@@ -1,9 +1,8 @@
|
||||
// @flow
|
||||
// See ElectronEventsBridge, AboutDialog and electron-app/main.js for handling the updates.
|
||||
|
||||
import { t, Trans } from '@lingui/macro';
|
||||
import { Trans } from '@lingui/macro';
|
||||
import React from 'react';
|
||||
import useAlertDialog from '../UI/Alert/useAlertDialog';
|
||||
|
||||
export type ElectronUpdateStatus = {
|
||||
message: string,
|
||||
@@ -97,53 +96,6 @@ export const useServiceWorkerUpdateStatus = () => {
|
||||
return serviceWorkerUpdateStatus;
|
||||
};
|
||||
|
||||
export const useServiceWorkerCheckAndAskToUpdate = () => {
|
||||
const serviceWorkerUpdateStatus = useServiceWorkerUpdateStatus();
|
||||
const { showConfirmation, showAlert } = useAlertDialog();
|
||||
React.useEffect(
|
||||
() => {
|
||||
if (serviceWorkerUpdateStatus === 'update-ready') {
|
||||
const timeoutId = setTimeout(() => {
|
||||
(async () => {
|
||||
const answer = await showConfirmation({
|
||||
title: t`New update available!`,
|
||||
message: t`A new version of GDevelop is available. Would you like to update now? The app will be reloaded.`,
|
||||
});
|
||||
if (answer) {
|
||||
try {
|
||||
await clearServiceWorkerAndForceReload();
|
||||
} catch (error) {
|
||||
console.error('Unable to update service worker', error);
|
||||
await showAlert({
|
||||
title: t`Unable to update`,
|
||||
message: t`Unable to update the app. Please close all your tabs and try again.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
})();
|
||||
}, 3000); // Let a bit of time for the app to load before showing the update dialog.
|
||||
return () => clearTimeout(timeoutId);
|
||||
}
|
||||
},
|
||||
[serviceWorkerUpdateStatus, showConfirmation, showAlert]
|
||||
);
|
||||
};
|
||||
|
||||
const clearServiceWorkerAndForceReload = async () => {
|
||||
const { serviceWorker } = navigator;
|
||||
if (!serviceWorker) {
|
||||
throw new Error('Service worker not available');
|
||||
}
|
||||
const registration = await serviceWorker.getRegistration();
|
||||
if (!registration) {
|
||||
throw new Error('Service worker registration not available');
|
||||
}
|
||||
await registration.unregister();
|
||||
const cacheKeys = await caches.keys();
|
||||
await Promise.all(cacheKeys.map(key => caches.delete(key)));
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
export const getServiceWorkerStatusLabel = (
|
||||
status: ServiceWorkerUpdateStatus
|
||||
) => {
|
||||
|
@@ -71,7 +71,6 @@ import {
|
||||
getElectronUpdateNotificationTitle,
|
||||
getElectronUpdateNotificationBody,
|
||||
type ElectronUpdateStatus,
|
||||
useServiceWorkerCheckAndAskToUpdate,
|
||||
} from './UpdaterTools';
|
||||
import { showWarningBox } from '../UI/Messages/MessageBox';
|
||||
import EmptyMessage from '../UI/EmptyMessage';
|
||||
@@ -665,8 +664,6 @@ const MainFrame = (props: Props) => {
|
||||
|
||||
useDiscordRichPresence(currentProject);
|
||||
|
||||
useServiceWorkerCheckAndAskToUpdate();
|
||||
|
||||
const closeProject = React.useCallback(
|
||||
(): Promise<void> => {
|
||||
setHasProjectOpened(false);
|
||||
|
@@ -1,12 +1,15 @@
|
||||
// @flow
|
||||
import * as React from 'react';
|
||||
import { t } from '@lingui/macro';
|
||||
|
||||
import * as React from 'react';
|
||||
import { List, ListItem } from '../UI/List';
|
||||
import ObjectSelector from '../ObjectsList/ObjectSelector';
|
||||
import EmptyMessage from '../UI/EmptyMessage';
|
||||
import { Column } from '../UI/Grid';
|
||||
import { Paper } from '@material-ui/core';
|
||||
import ListIcon from '../UI/ListIcon';
|
||||
import ObjectsRenderingService from '../ObjectsRendering/ObjectsRenderingService';
|
||||
import getObjectByName from '../Utils/GetObjectByName';
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
const styles = {
|
||||
@@ -78,12 +81,28 @@ const ObjectGroupEditor = ({
|
||||
.getAllObjectsNames()
|
||||
.toJSArray()
|
||||
.map(objectName => {
|
||||
let object = getObjectByName(
|
||||
globalObjectsContainer,
|
||||
objectsContainer,
|
||||
objectName
|
||||
);
|
||||
const icon =
|
||||
project && object ? (
|
||||
<ListIcon
|
||||
iconSize={24}
|
||||
src={ObjectsRenderingService.getThumbnail(
|
||||
project,
|
||||
object.getConfiguration()
|
||||
)}
|
||||
/>
|
||||
) : null;
|
||||
return (
|
||||
<ListItem
|
||||
key={objectName}
|
||||
primaryText={objectName}
|
||||
displayRemoveButton
|
||||
onRemove={() => removeObject(objectName)}
|
||||
leftIcon={icon}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@@ -20,6 +20,7 @@ import { showErrorBox } from '../UI/Messages/MessageBox';
|
||||
import optionalRequire from '../Utils/OptionalRequire';
|
||||
import Text from '../UI/Text';
|
||||
import { ColumnStackLayout } from '../UI/Layout';
|
||||
import AlertMessage from '../UI/AlertMessage';
|
||||
const path = optionalRequire('path');
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
@@ -39,6 +40,7 @@ type State = {|
|
||||
androidIconResourceNames: Array<string>,
|
||||
androidWindowSplashScreenAnimatedIconResourceName: string,
|
||||
iosIconResourceNames: Array<string>,
|
||||
displayLiluoThumbnailWarning: boolean,
|
||||
|};
|
||||
|
||||
const desktopSizes = [512];
|
||||
@@ -96,6 +98,7 @@ export default class PlatformSpecificAssetsDialog extends React.Component<
|
||||
iosIconResourceNames: iosSizes.map(size =>
|
||||
platformSpecificAssets.get('ios', `icon-${size}`)
|
||||
),
|
||||
displayLiluoThumbnailWarning: false,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -299,6 +302,7 @@ export default class PlatformSpecificAssetsDialog extends React.Component<
|
||||
androidIconResourceNames,
|
||||
androidWindowSplashScreenAnimatedIconResourceName,
|
||||
iosIconResourceNames,
|
||||
displayLiluoThumbnailWarning,
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
@@ -324,9 +328,23 @@ export default class PlatformSpecificAssetsDialog extends React.Component<
|
||||
onChange={resourceName => {
|
||||
this.setState({
|
||||
thumbnailResourceName: resourceName,
|
||||
displayLiluoThumbnailWarning:
|
||||
resourceName !== this.state.thumbnailResourceName,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
{displayLiluoThumbnailWarning ? (
|
||||
<Line>
|
||||
<AlertMessage kind="warning">
|
||||
<Trans>
|
||||
You're about to change the thumbnail displayed on Liluo.io for
|
||||
your game. Once you have applied changes here, you will then
|
||||
need to publish a new version of your game on Liluo.io so that
|
||||
this new thumbnail is used.
|
||||
</Trans>
|
||||
</AlertMessage>
|
||||
</Line>
|
||||
) : null}
|
||||
<Line justifyContent="center">
|
||||
{isResizeSupported() ? (
|
||||
<RaisedButton
|
||||
|
@@ -96,6 +96,7 @@ const AchievementList = ({
|
||||
>
|
||||
<Text
|
||||
noMargin
|
||||
size="sub-title"
|
||||
style={
|
||||
achievementWithBadgeData.unlockedAt
|
||||
? styles.unlockedAchievement
|
||||
|
@@ -649,6 +649,9 @@ export default class ProjectManager extends React.Component<Props, State> {
|
||||
eventsFunctionsExtensionsError,
|
||||
onReloadEventsFunctionsExtensions,
|
||||
onInstallExtension,
|
||||
resourceSources,
|
||||
onChooseResource,
|
||||
resourceExternalEditors,
|
||||
} = this.props;
|
||||
const {
|
||||
renamedItemKind,
|
||||
@@ -1137,6 +1140,9 @@ export default class ProjectManager extends React.Component<Props, State> {
|
||||
);
|
||||
this._onOpenLayoutProperties(null);
|
||||
}}
|
||||
resourceSources={resourceSources}
|
||||
resourceExternalEditors={resourceExternalEditors}
|
||||
onChooseResource={onChooseResource}
|
||||
/>
|
||||
)}
|
||||
{!!this.state.editedVariablesLayout && (
|
||||
|
53
newIDE/app/src/SceneEditor/BehaviorSharedPropertiesEditor.js
Normal file
53
newIDE/app/src/SceneEditor/BehaviorSharedPropertiesEditor.js
Normal file
@@ -0,0 +1,53 @@
|
||||
// @flow
|
||||
import { Trans } from '@lingui/macro';
|
||||
|
||||
import * as React from 'react';
|
||||
import PropertiesEditor from '../PropertiesEditor';
|
||||
import propertiesMapToSchema from '../PropertiesEditor/PropertiesMapToSchema';
|
||||
import EmptyMessage from '../UI/EmptyMessage';
|
||||
import { Column } from '../UI/Grid';
|
||||
import {
|
||||
type ResourceSource,
|
||||
type ChooseResourceFunction,
|
||||
} from '../ResourcesList/ResourceSource';
|
||||
import { type ResourceExternalEditor } from '../ResourcesList/ResourceExternalEditor.flow';
|
||||
|
||||
type Props = {|
|
||||
behaviorSharedData: gdBehaviorsSharedData,
|
||||
project: gdProject,
|
||||
resourceSources: Array<ResourceSource>,
|
||||
onChooseResource: ChooseResourceFunction,
|
||||
resourceExternalEditors: Array<ResourceExternalEditor>,
|
||||
|};
|
||||
|
||||
export default class BehaviorSharedPropertiesEditor extends React.Component<Props> {
|
||||
render() {
|
||||
const { behaviorSharedData } = this.props;
|
||||
|
||||
const propertiesSchema = propertiesMapToSchema(
|
||||
behaviorSharedData.getProperties(),
|
||||
behavior => behavior.getProperties(),
|
||||
(behavior, name, value) => {
|
||||
behavior.updateProperty(name, value);
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<Column expand>
|
||||
{propertiesSchema.length ? (
|
||||
<PropertiesEditor
|
||||
schema={propertiesSchema}
|
||||
instances={[behaviorSharedData]}
|
||||
/>
|
||||
) : (
|
||||
<EmptyMessage>
|
||||
<Trans>
|
||||
There is nothing to configure for this behavior. You can still use
|
||||
events to interact with the object and this behavior.
|
||||
</Trans>
|
||||
</EmptyMessage>
|
||||
)}
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
}
|
@@ -7,7 +7,7 @@ import RaisedButton from '../UI/RaisedButton';
|
||||
import Dialog, { DialogPrimaryButton } from '../UI/Dialog';
|
||||
import ColorField from '../UI/ColorField';
|
||||
import EmptyMessage from '../UI/EmptyMessage';
|
||||
import PropertiesEditor from '../PropertiesEditor';
|
||||
import BehaviorSharedPropertiesEditor from './BehaviorSharedPropertiesEditor';
|
||||
import propertiesMapToSchema from '../PropertiesEditor/PropertiesMapToSchema';
|
||||
import some from 'lodash/some';
|
||||
import Checkbox from '../UI/Checkbox';
|
||||
@@ -18,6 +18,19 @@ import {
|
||||
rgbStringAndAlphaToRGBColor,
|
||||
type RGBColor,
|
||||
} from '../Utils/ColorTransformer';
|
||||
import HelpIcon from '../UI/HelpIcon';
|
||||
import { Column, Line } from '../UI/Grid';
|
||||
import DismissableTutorialMessage from '../Hints/DismissableTutorialMessage';
|
||||
import { Accordion, AccordionHeader, AccordionBody } from '../UI/Accordion';
|
||||
import { IconContainer } from '../UI/IconContainer';
|
||||
import { getBehaviorTutorialIds } from '../Utils/GDevelopServices/Tutorial';
|
||||
import ScrollView from '../UI/ScrollView';
|
||||
import {
|
||||
type ResourceSource,
|
||||
type ChooseResourceFunction,
|
||||
} from '../ResourcesList/ResourceSource';
|
||||
import { type ResourceExternalEditor } from '../ResourcesList/ResourceExternalEditor.flow';
|
||||
|
||||
const gd: libGDevelop = global.gd;
|
||||
|
||||
type Props = {|
|
||||
@@ -28,6 +41,9 @@ type Props = {|
|
||||
onClose: () => void,
|
||||
onOpenMoreSettings?: ?() => void,
|
||||
onEditVariables: () => void,
|
||||
resourceSources: Array<ResourceSource>,
|
||||
onChooseResource: ChooseResourceFunction,
|
||||
resourceExternalEditors: Array<ResourceExternalEditor>,
|
||||
|};
|
||||
|
||||
type State = {|
|
||||
@@ -102,16 +118,8 @@ export default class ScenePropertiesDialog extends Component<Props, State> {
|
||||
.toJSArray();
|
||||
|
||||
const propertiesEditors = allBehaviorSharedDataNames
|
||||
.map(name => {
|
||||
const behaviorSharedData = layout.getBehaviorSharedData(name);
|
||||
|
||||
// TODO Check if this extra check is needed.
|
||||
const behaviorMetadata = gd.MetadataProvider.getBehaviorMetadata(
|
||||
gd.JsPlatform.get(),
|
||||
behaviorSharedData.getTypeName()
|
||||
);
|
||||
if (gd.MetadataProvider.isBadBehaviorMetadata(behaviorMetadata))
|
||||
return null;
|
||||
.map(behaviorName => {
|
||||
const behaviorSharedData = layout.getBehaviorSharedData(behaviorName);
|
||||
|
||||
if (isNullPtr(gd, behaviorSharedData)) return null;
|
||||
|
||||
@@ -123,14 +131,85 @@ export default class ScenePropertiesDialog extends Component<Props, State> {
|
||||
behaviorSharedData.updateProperty(name, value);
|
||||
}
|
||||
);
|
||||
const behaviorTypeName = behaviorSharedData.getTypeName();
|
||||
|
||||
const behaviorMetadata = gd.MetadataProvider.getBehaviorMetadata(
|
||||
gd.JsPlatform.get(),
|
||||
behaviorTypeName
|
||||
);
|
||||
const tutorialIds = getBehaviorTutorialIds(behaviorTypeName);
|
||||
// TODO Make this a functional component to use PreferencesContext
|
||||
const enabledTutorialIds = [];
|
||||
const iconUrl = behaviorMetadata.getIconFilename();
|
||||
|
||||
return (
|
||||
!!propertiesSchema.length && (
|
||||
<PropertiesEditor
|
||||
key={name}
|
||||
schema={propertiesSchema}
|
||||
instances={[behaviorSharedData]}
|
||||
/>
|
||||
<Accordion
|
||||
key={behaviorName}
|
||||
defaultExpanded
|
||||
id={`behavior-parameters-${behaviorName}`}
|
||||
>
|
||||
<AccordionHeader
|
||||
actions={[
|
||||
<HelpIcon
|
||||
key="help"
|
||||
size="small"
|
||||
helpPagePath={behaviorMetadata.getHelpPath()}
|
||||
/>,
|
||||
]}
|
||||
>
|
||||
{iconUrl ? (
|
||||
<IconContainer
|
||||
src={iconUrl}
|
||||
alt={behaviorMetadata.getFullName()}
|
||||
size={20}
|
||||
/>
|
||||
) : null}
|
||||
<Column expand>
|
||||
<TextField
|
||||
value={behaviorName}
|
||||
margin="none"
|
||||
fullWidth
|
||||
disabled
|
||||
onChange={(e, text) => {}}
|
||||
id={`behavior-${behaviorName}-name-text-field`}
|
||||
/>
|
||||
</Column>
|
||||
</AccordionHeader>
|
||||
<AccordionBody>
|
||||
<Column
|
||||
expand
|
||||
noMargin
|
||||
// Avoid Physics2 behavior overflow on small screens
|
||||
noOverflowParent
|
||||
>
|
||||
{enabledTutorialIds.length ? (
|
||||
<Line>
|
||||
<ColumnStackLayout expand>
|
||||
{tutorialIds.map(tutorialId => (
|
||||
<DismissableTutorialMessage
|
||||
key={tutorialId}
|
||||
tutorialId={tutorialId}
|
||||
/>
|
||||
))}
|
||||
</ColumnStackLayout>
|
||||
</Line>
|
||||
) : null}
|
||||
<Line>
|
||||
<BehaviorSharedPropertiesEditor
|
||||
key={behaviorName}
|
||||
behaviorSharedData={behaviorSharedData}
|
||||
project={this.props.project}
|
||||
resourceSources={this.props.resourceSources}
|
||||
onChooseResource={this.props.onChooseResource}
|
||||
resourceExternalEditors={
|
||||
this.props.resourceExternalEditors
|
||||
}
|
||||
/>
|
||||
</Line>
|
||||
</Column>
|
||||
</AccordionBody>
|
||||
</Accordion>
|
||||
)
|
||||
);
|
||||
})
|
||||
@@ -156,55 +235,57 @@ export default class ScenePropertiesDialog extends Component<Props, State> {
|
||||
open={this.props.open}
|
||||
maxWidth="sm"
|
||||
>
|
||||
<ColumnStackLayout expand noMargin>
|
||||
<TextField
|
||||
floatingLabelText={<Trans>Window title</Trans>}
|
||||
fullWidth
|
||||
type="text"
|
||||
value={this.state.windowTitle}
|
||||
onChange={(e, value) => this.setState({ windowTitle: value })}
|
||||
/>
|
||||
<Checkbox
|
||||
checked={this.state.shouldStopSoundsOnStartup}
|
||||
label={<Trans>Stop music and sounds on startup</Trans>}
|
||||
onCheck={(e, check) =>
|
||||
this.setState({
|
||||
shouldStopSoundsOnStartup: check,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<ColorField
|
||||
floatingLabelText={<Trans>Scene background color</Trans>}
|
||||
fullWidth
|
||||
disableAlpha
|
||||
color={rgbColorToRGBString(this.state.backgroundColor)}
|
||||
onChange={color =>
|
||||
this.setState({
|
||||
backgroundColor: rgbStringAndAlphaToRGBColor(color),
|
||||
})
|
||||
}
|
||||
/>
|
||||
{!some(propertiesEditors) && (
|
||||
<EmptyMessage>
|
||||
<Trans>
|
||||
Any additional properties will appear here if you add behaviors
|
||||
to objects, like Physics behavior.
|
||||
</Trans>
|
||||
</EmptyMessage>
|
||||
)}
|
||||
{propertiesEditors}
|
||||
{this.props.onOpenMoreSettings && (
|
||||
<RaisedButton
|
||||
label={<Trans>Open advanced settings</Trans>}
|
||||
<ScrollView>
|
||||
<ColumnStackLayout expand noMargin>
|
||||
<TextField
|
||||
floatingLabelText={<Trans>Window title</Trans>}
|
||||
fullWidth
|
||||
onClick={() => {
|
||||
if (this.props.onOpenMoreSettings)
|
||||
this.props.onOpenMoreSettings();
|
||||
this.props.onClose();
|
||||
}}
|
||||
type="text"
|
||||
value={this.state.windowTitle}
|
||||
onChange={(e, value) => this.setState({ windowTitle: value })}
|
||||
/>
|
||||
)}
|
||||
</ColumnStackLayout>
|
||||
<Checkbox
|
||||
checked={this.state.shouldStopSoundsOnStartup}
|
||||
label={<Trans>Stop music and sounds on startup</Trans>}
|
||||
onCheck={(e, check) =>
|
||||
this.setState({
|
||||
shouldStopSoundsOnStartup: check,
|
||||
})
|
||||
}
|
||||
/>
|
||||
<ColorField
|
||||
floatingLabelText={<Trans>Scene background color</Trans>}
|
||||
fullWidth
|
||||
disableAlpha
|
||||
color={rgbColorToRGBString(this.state.backgroundColor)}
|
||||
onChange={color =>
|
||||
this.setState({
|
||||
backgroundColor: rgbStringAndAlphaToRGBColor(color),
|
||||
})
|
||||
}
|
||||
/>
|
||||
{!some(propertiesEditors) && (
|
||||
<EmptyMessage>
|
||||
<Trans>
|
||||
Any additional properties will appear here if you add
|
||||
behaviors to objects, like Physics behavior.
|
||||
</Trans>
|
||||
</EmptyMessage>
|
||||
)}
|
||||
{propertiesEditors}
|
||||
{this.props.onOpenMoreSettings && (
|
||||
<RaisedButton
|
||||
label={<Trans>Open advanced settings</Trans>}
|
||||
fullWidth
|
||||
onClick={() => {
|
||||
if (this.props.onOpenMoreSettings)
|
||||
this.props.onOpenMoreSettings();
|
||||
this.props.onClose();
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</ColumnStackLayout>
|
||||
</ScrollView>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
|
@@ -57,27 +57,27 @@ const Toolbar = (props: Props) => {
|
||||
<ToolbarIcon
|
||||
onClick={props.openObjectsList}
|
||||
src="res/ribbon_default/objects64.png"
|
||||
tooltip={t`Open the objects editor`}
|
||||
tooltip={t`Open Objects Panel`}
|
||||
/>
|
||||
<ToolbarIcon
|
||||
onClick={props.openObjectGroupsList}
|
||||
src={'res/ribbon_default/objectsgroups64.png'}
|
||||
tooltip={t`Open the objects groups editor`}
|
||||
tooltip={t`Open Object Groups Panel`}
|
||||
/>
|
||||
<ToolbarIcon
|
||||
onClick={props.openProperties}
|
||||
src="res/ribbon_default/editprop32.png"
|
||||
tooltip={t`Open the properties panel`}
|
||||
tooltip={t`Open Properties Panel`}
|
||||
/>
|
||||
<ToolbarIcon
|
||||
onClick={props.toggleInstancesList}
|
||||
src="res/ribbon_default/ObjectsPositionsList32.png"
|
||||
tooltip={t`Open the list of instances`}
|
||||
tooltip={t`Open Instances List Panel`}
|
||||
/>
|
||||
<ToolbarIcon
|
||||
onClick={props.toggleLayersList}
|
||||
src="res/ribbon_default/layers32.png"
|
||||
tooltip={t`Open the layers editor`}
|
||||
tooltip={t`Open Layers Panel`}
|
||||
/>
|
||||
<ToolbarSeparator />
|
||||
<ToolbarIcon
|
||||
|
@@ -811,6 +811,44 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
done(true);
|
||||
};
|
||||
|
||||
_onMoveInstancesZOrder = (where: 'front' | 'back') => {
|
||||
const selectedInstances = this.instancesSelection.getSelectedInstances();
|
||||
|
||||
const layerNames = selectedInstances.reduce(
|
||||
(acc: Set<string>, instance) => {
|
||||
if (!instance.isLocked()) acc.add(instance.getLayer());
|
||||
return acc;
|
||||
},
|
||||
new Set()
|
||||
);
|
||||
|
||||
const highestZOrderFinder = new gd.HighestZOrderFinder();
|
||||
|
||||
const extremeZOrderByLayerName = {};
|
||||
layerNames.forEach(layerName => {
|
||||
highestZOrderFinder.reset();
|
||||
highestZOrderFinder.restrictSearchToLayer(layerName);
|
||||
this.props.initialInstances.iterateOverInstances(highestZOrderFinder);
|
||||
extremeZOrderByLayerName[layerName] =
|
||||
where === 'back'
|
||||
? highestZOrderFinder.getLowestZOrder()
|
||||
: highestZOrderFinder.getHighestZOrder();
|
||||
});
|
||||
highestZOrderFinder.delete();
|
||||
|
||||
selectedInstances.forEach(instance => {
|
||||
if (!instance.isLocked()) {
|
||||
const extremeZOrder = extremeZOrderByLayerName[instance.getLayer()];
|
||||
// If instance is already at the extreme z order, do nothing.
|
||||
if (instance.getZOrder() === extremeZOrder) return;
|
||||
|
||||
instance.setZOrder(extremeZOrder + (where === 'front' ? 1 : -1));
|
||||
}
|
||||
});
|
||||
this.forceUpdateInstancesList();
|
||||
this.forceUpdatePropertiesEditor();
|
||||
};
|
||||
|
||||
_onDeleteGroup = (
|
||||
groupWithContext: GroupWithContext,
|
||||
done: boolean => void
|
||||
@@ -1013,11 +1051,27 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
},
|
||||
{
|
||||
label: i18n._(t`Duplicate`),
|
||||
enabled: this.instancesSelection.hasSelectedInstances(),
|
||||
click: () => {
|
||||
this.duplicateSelection();
|
||||
},
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: i18n._(t`Bring to front`),
|
||||
enabled: this.instancesSelection.hasSelectedInstances(),
|
||||
click: () => {
|
||||
this._onMoveInstancesZOrder('front');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n._(t`Send to back`),
|
||||
enabled: this.instancesSelection.hasSelectedInstances(),
|
||||
click: () => {
|
||||
this._onMoveInstancesZOrder('back');
|
||||
},
|
||||
},
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: i18n._(t`Delete`),
|
||||
click: () => this.deleteSelection(),
|
||||
@@ -1324,7 +1378,7 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
},
|
||||
'instances-list': {
|
||||
type: 'secondary',
|
||||
title: t`Instances list`,
|
||||
title: t`Instances List`,
|
||||
renderEditor: () => (
|
||||
<InstancesList
|
||||
instances={initialInstances}
|
||||
@@ -1735,6 +1789,9 @@ export default class SceneEditor extends React.Component<Props, State> {
|
||||
onApply={() => this.openSceneProperties(false)}
|
||||
onEditVariables={() => this.editLayoutVariables(true)}
|
||||
onOpenMoreSettings={this.props.onOpenMoreSettings}
|
||||
resourceSources={resourceSources}
|
||||
resourceExternalEditors={resourceExternalEditors}
|
||||
onChooseResource={onChooseResource}
|
||||
/>
|
||||
)}
|
||||
{!!this.state.layoutVariablesDialogOpen && (
|
||||
|
@@ -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');
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user