Add a command to generate an action and an expression for a custom object property (#4620)

* Don't show in changelog
This commit is contained in:
D8H
2022-12-04 20:27:17 +01:00
committed by GitHub
parent 7620bac88a
commit dc146a7411
16 changed files with 449 additions and 87 deletions

View File

@@ -55,6 +55,10 @@ void Instruction::SetParameter(std::size_t nb, const gd::Expression& val) {
parameters[nb] = val;
}
void Instruction::AddParameter(const gd::Expression& val) {
parameters.push_back(val);
}
std::shared_ptr<Instruction> GD_CORE_API
CloneRememberingOriginalElement(std::shared_ptr<Instruction> instruction) {
std::shared_ptr<Instruction> copy =

View File

@@ -123,6 +123,11 @@ class GD_CORE_API Instruction {
*/
void SetParameter(std::size_t nb, const gd::Expression& val);
/** Add a parameter at the end
* \param val The new value of the parameter
*/
void AddParameter(const gd::Expression& val);
/** \brief Get a reference to the std::vector containing the parameters.
* \return A std::vector containing the parameters
*/

View File

@@ -10,6 +10,7 @@
#include "GDCore/Extensions/Metadata/ValueTypeMetadata.h"
#include "GDCore/Extensions/PlatformExtension.h"
#include "GDCore/Project/EventsBasedBehavior.h"
#include "GDCore/Project/EventsBasedObject.h"
#include "GDCore/Project/EventsFunctionsExtension.h"
#include "GDCore/Project/Project.h"
#include "GDCore/Project/PropertyDescriptor.h"
@@ -17,19 +18,37 @@
namespace gd {
void PropertyFunctionGenerator::GenerateGetterAndSetter(
void PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
gd::Project &project, gd::EventsFunctionsExtension &extension,
gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::NamedPropertyDescriptor &property, bool isSharedProperties) {
GenerateGetterAndSetter(project, extension, eventsBasedBehavior, property,
eventsBasedBehavior.GetObjectType(), true,
isSharedProperties);
}
void PropertyFunctionGenerator::GenerateObjectGetterAndSetter(
gd::Project &project, gd::EventsFunctionsExtension &extension,
gd::EventsBasedObject &eventsBasedObject,
const gd::NamedPropertyDescriptor &property) {
GenerateGetterAndSetter(project, extension, eventsBasedObject, property, "",
false, false);
}
void PropertyFunctionGenerator::GenerateGetterAndSetter(
gd::Project &project, gd::EventsFunctionsExtension &extension,
gd::AbstractEventsBasedEntity &eventsBasedEntity,
const gd::NamedPropertyDescriptor &property, const gd::String &objectType,
bool isBehavior, bool isSharedProperties) {
auto &propertyName = property.GetName();
auto &functionsContainer = eventsBasedBehavior.GetEventsFunctions();
auto &functionsContainer = eventsBasedEntity.GetEventsFunctions();
gd::String capitalizedName = CapitalizeFirstLetter(property.GetName());
gd::String setterName = "Set" + capitalizedName;
gd::String functionGroupName =
(eventsBasedBehavior.GetFullName().empty()
? eventsBasedBehavior.GetName()
: eventsBasedBehavior.GetFullName()) +
(eventsBasedEntity.GetFullName().empty()
? eventsBasedEntity.GetName()
: eventsBasedEntity.GetFullName()) +
(property.GetGroup().empty()
? ""
: " " + UnCapitalizeFirstLetter(property.GetGroup())) +
@@ -51,17 +70,14 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
"objects using the behavior."
: "");
gd::String behaviorFullType = gd::PlatformExtension::GetBehaviorFullType(
extension.GetName(), eventsBasedBehavior.GetName());
gd::String propertyGetterName =
(isSharedProperties ? "SharedProperty" : "Property") + property.GetName();
gd::String getterType =
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
extension.GetName(), eventsBasedBehavior.GetName(),
propertyGetterName);
extension.GetName(), eventsBasedEntity.GetName(), propertyGetterName);
gd::String setterType =
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
extension.GetName(), eventsBasedBehavior.GetName(),
extension.GetName(), eventsBasedEntity.GetName(),
"Set" + propertyGetterName);
gd::String getterName = capitalizedName;
@@ -98,24 +114,24 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
if (property.GetType() == "Boolean") {
gd::Instruction condition;
condition.SetType(getterType);
condition.SetParametersCount(2);
condition.SetParameter(0, "Object");
condition.SetParameter(1, "Behavior");
condition.AddParameter("Object");
if (isBehavior) {
condition.AddParameter("Behavior");
}
event.GetConditions().Insert(condition, 0);
gd::Instruction action;
action.SetType("SetReturnBoolean");
action.SetParametersCount(1);
action.SetParameter(0, "True");
action.AddParameter("True");
event.GetActions().Insert(action, 0);
} else {
gd::Instruction action;
action.SetType("SetReturn" + numberOrString);
action.SetParametersCount(1);
gd::String receiver = isBehavior ? "Object.Behavior::" : "Object.";
gd::String propertyPrefix =
(isSharedProperties ? "SharedProperty" : "Property");
action.SetParameter(0, "Object.Behavior::" + propertyPrefix +
property.GetName() + "()");
action.AddParameter(receiver + propertyPrefix + property.GetName() +
"()");
event.GetActions().Insert(action, 0);
}
}
@@ -129,25 +145,35 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
.SetGroup(functionGroupName)
.SetDescription("Change " + descriptionSubject)
.SetSentence("_PARAM0_ " + UnCapitalizeFirstLetter(propertyLabel) +
": _PARAM2_");
(isBehavior ? ": _PARAM2_" : ": _PARAM1_"));
gd::ParameterMetadata objectParameter;
objectParameter.SetType("object")
.SetName("Object")
.SetDescription("Object")
.SetExtraInfo(eventsBasedBehavior.GetObjectType());
gd::ParameterMetadata behaviorParameter;
behaviorParameter.SetType("behavior")
.SetName("Behavior")
.SetDescription("Behavior")
.SetExtraInfo(behaviorFullType);
.SetExtraInfo(objectType);
if (!isBehavior) {
gd::String objectFullType = gd::PlatformExtension::GetObjectFullType(
extension.GetName(), eventsBasedEntity.GetName());
objectParameter.SetExtraInfo(objectFullType);
}
setter.GetParameters().push_back(objectParameter);
if (isBehavior) {
gd::ParameterMetadata behaviorParameter;
gd::String behaviorFullType =
gd::PlatformExtension::GetBehaviorFullType(
extension.GetName(), eventsBasedEntity.GetName());
behaviorParameter.SetType("behavior")
.SetName("Behavior")
.SetDescription("Behavior")
.SetExtraInfo(behaviorFullType);
setter.GetParameters().push_back(behaviorParameter);
}
gd::ParameterMetadata valueParameter;
valueParameter.SetType("yesorno")
.SetName("Value")
.SetDescription(capitalizedName)
.SetOptional(true)
.SetDefaultValue("yes");
setter.GetParameters().push_back(objectParameter);
setter.GetParameters().push_back(behaviorParameter);
setter.GetParameters().push_back(valueParameter);
} else {
setter.SetFunctionType(gd::EventsFunction::ActionWithOperator);
@@ -162,16 +188,18 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
gd::Instruction condition;
condition.SetType("GetArgumentAsBoolean");
condition.SetParametersCount(1);
condition.SetParameter(0, "\"Value\"");
condition.AddParameter("\"Value\"");
event.GetConditions().Insert(condition, 0);
gd::Instruction action;
action.SetType(setterType);
action.SetParametersCount(3);
action.SetParameter(0, "Object");
action.SetParameter(1, "Behavior");
action.SetParameter(2, "yes");
action.AddParameter("Object");
if (isBehavior) {
action.AddParameter("Behavior");
action.AddParameter("yes");
} else {
action.AddParameter("yes");
}
event.GetActions().Insert(action, 0);
}
{
@@ -181,17 +209,19 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
gd::Instruction condition;
condition.SetType("GetArgumentAsBoolean");
condition.SetParametersCount(1);
condition.SetParameter(0, "\"Value\"");
condition.AddParameter("\"Value\"");
condition.SetInverted(true);
event.GetConditions().Insert(condition, 0);
gd::Instruction action;
action.SetType(setterType);
action.SetParametersCount(3);
action.SetParameter(0, "Object");
action.SetParameter(1, "Behavior");
action.SetParameter(2, "no");
action.AddParameter("Object");
if (isBehavior) {
action.AddParameter("Behavior");
action.AddParameter("no");
} else {
action.AddParameter("no");
}
event.GetActions().Insert(action, 0);
}
} else {
@@ -201,18 +231,24 @@ void PropertyFunctionGenerator::GenerateGetterAndSetter(
gd::Instruction action;
action.SetType(setterType);
action.SetParametersCount(4);
action.SetParameter(0, "Object");
action.SetParameter(1, "Behavior");
action.SetParameter(2, "=");
action.SetParameter(3, "GetArgumentAs" + numberOrString + "(\"Value\")");
action.AddParameter("Object");
gd::String parameterGetterCall =
"GetArgumentAs" + numberOrString + "(\"Value\")";
if (isBehavior) {
action.AddParameter("Behavior");
action.AddParameter("=");
action.AddParameter(parameterGetterCall);
} else {
action.AddParameter("=");
action.AddParameter(parameterGetterCall);
}
event.GetActions().Insert(action, 0);
}
}
}
bool PropertyFunctionGenerator::CanGenerateGetterAndSetter(
const gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::AbstractEventsBasedEntity &eventsBasedEntity,
const gd::NamedPropertyDescriptor &property) {
auto &type = property.GetType();
if (type != "Boolean" && type != "Number" && type != "String" &&
@@ -220,7 +256,7 @@ bool PropertyFunctionGenerator::CanGenerateGetterAndSetter(
return false;
}
auto &functionsContainer = eventsBasedBehavior.GetEventsFunctions();
auto &functionsContainer = eventsBasedEntity.GetEventsFunctions();
auto getterName = CapitalizeFirstLetter(property.GetName());
auto setterName = "Set" + getterName;
return !functionsContainer.HasEventsFunctionNamed(setterName) &&

View File

@@ -11,6 +11,8 @@ class String;
class Project;
class EventsFunctionsExtension;
class EventsBasedBehavior;
class EventsBasedObject;
class AbstractEventsBasedEntity;
class PropertyDescriptor;
class NamedPropertyDescriptor;
} // namespace gd
@@ -23,19 +25,33 @@ namespace gd {
class GD_CORE_API PropertyFunctionGenerator {
public:
/**
* \brief Generate a getter and a setter for the given property.
* \brief Generate a getter and a setter for the given behavior property.
*/
static void GenerateGetterAndSetter(
static void GenerateBehaviorGetterAndSetter(
gd::Project &project, gd::EventsFunctionsExtension &extension,
gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::NamedPropertyDescriptor &property, bool isSharedProperties);
static bool
CanGenerateGetterAndSetter(const gd::EventsBasedBehavior &eventsBasedBehavior,
const gd::NamedPropertyDescriptor &property);
/**
* \brief Generate a getter and a setter for the given object property.
*/
static void
GenerateObjectGetterAndSetter(gd::Project &project,
gd::EventsFunctionsExtension &extension,
gd::EventsBasedObject &eventsBasedObject,
const gd::NamedPropertyDescriptor &property);
static bool CanGenerateGetterAndSetter(
const gd::AbstractEventsBasedEntity &eventsBasedEntity,
const gd::NamedPropertyDescriptor &property);
~PropertyFunctionGenerator();
private:
static void GenerateGetterAndSetter(
gd::Project &project, gd::EventsFunctionsExtension &extension,
gd::AbstractEventsBasedEntity &eventsBasedEntity,
const gd::NamedPropertyDescriptor &property, const gd::String &objectType,
bool isBehavior, bool isSharedProperties);
static gd::String CapitalizeFirstLetter(const gd::String &string);
static gd::String UnCapitalizeFirstLetter(const gd::String &string);
static gd::String

View File

@@ -29,10 +29,20 @@ CreateBehavior(gd::EventsFunctionsExtension &eventsExtension) {
eventsBasedBehavior.SetObjectType("");
return eventsBasedBehavior;
};
gd::EventsBasedObject &
CreateObject(gd::EventsFunctionsExtension &eventsExtension) {
auto &eventsBasedObject = eventsExtension.GetEventsBasedObjects().InsertNew(
"MyEventsBasedObject", 0);
eventsBasedObject.SetFullName("My events based object");
eventsBasedObject.SetDescription("An events based object for test");
return eventsBasedObject;
};
} // namespace
TEST_CASE("PropertyFunctionGenerator", "[common]") {
SECTION("Can generate functions for a number property") {
SECTION("Can generate functions for a number property in a behavior") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
@@ -47,7 +57,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
.SetDescription("The angle of the trajectory direction.")
.SetGroup("Movement");
gd::PropertyFunctionGenerator::GenerateGetterAndSetter(
gd::PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
project, extension, behavior, property, false);
REQUIRE(
@@ -119,7 +129,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
}
}
SECTION("Can generate functions for a choice property") {
SECTION("Can generate functions for a choice property in a behavior") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
@@ -137,7 +147,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
property.GetExtraInfo().push_back("Dot shape");
property.GetExtraInfo().push_back("Bounding disk");
gd::PropertyFunctionGenerator::GenerateGetterAndSetter(
gd::PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
project, extension, behavior, property, false);
REQUIRE(
@@ -155,7 +165,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
"[\"Dot shape\",\"Bounding disk\"]");
}
SECTION("Can generate functions for a boolean property") {
SECTION("Can generate functions for a boolean property in a behavior") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
@@ -170,7 +180,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
"The rotation follows movements done by this behavior only.")
.SetGroup("Movement");
gd::PropertyFunctionGenerator::GenerateGetterAndSetter(
gd::PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
project, extension, behavior, property, false);
REQUIRE(behavior.GetEventsFunctions().HasEventsFunctionNamed("Rotate"));
@@ -284,6 +294,249 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
REQUIRE(setterYesAction.GetParameter(2).GetPlainString() == "yes");
}
}
SECTION("Can generate functions for a number property in an object") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
auto &extension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &object = CreateObject(extension);
auto &property =
object.GetPropertyDescriptors().InsertNew("MovementAngle", 0);
property.SetType("Number")
.SetLabel("Movement angle")
.SetDescription("The angle of the trajectory direction.")
.SetGroup("Movement");
gd::PropertyFunctionGenerator::GenerateObjectGetterAndSetter(
project, extension, object, property);
REQUIRE(
object.GetEventsFunctions().HasEventsFunctionNamed("MovementAngle"));
REQUIRE(
object.GetEventsFunctions().HasEventsFunctionNamed("SetMovementAngle"));
{
auto &getter =
object.GetEventsFunctions().GetEventsFunction("MovementAngle");
REQUIRE(getter.GetFunctionType() ==
gd::EventsFunction::ExpressionAndCondition);
REQUIRE(getter.GetExpressionType().GetName() == "expression");
REQUIRE(getter.GetFullName() == "Movement angle");
REQUIRE(getter.GetGroup() ==
"My events based object movement configuration");
REQUIRE(getter.GetDescription() ==
"the movement angle of the object. The "
"angle of the trajectory direction.");
REQUIRE(getter.GetSentence() == "the movement angle");
// Object parameter is added automatically.
REQUIRE(getter.GetParameters().size() == 0);
REQUIRE(getter.GetEvents().GetEventsCount() == 1);
REQUIRE(getter.GetEvents().GetEvent(0).GetType() ==
"BuiltinCommonInstructions::Standard");
auto &getterEvent =
dynamic_cast<gd::StandardEvent &>(getter.GetEvents().GetEvent(0));
REQUIRE(getterEvent.GetConditions().size() == 0);
REQUIRE(getterEvent.GetActions().size() == 1);
auto &getterAction = getterEvent.GetActions().at(0);
REQUIRE(getterAction.GetType() == "SetReturnNumber");
REQUIRE(getterAction.GetParametersCount() == 1);
REQUIRE(getterAction.GetParameter(0).GetPlainString() ==
"Object.PropertyMovementAngle()");
}
{
auto &setter =
object.GetEventsFunctions().GetEventsFunction("SetMovementAngle");
REQUIRE(setter.GetFunctionType() ==
gd::EventsFunction::ActionWithOperator);
REQUIRE(setter.GetGetterName() == "MovementAngle");
// These fields are deducted from the getter.
REQUIRE(setter.GetFullName() == "");
REQUIRE(setter.GetGroup() == "");
REQUIRE(setter.GetDescription() == "");
REQUIRE(setter.GetSentence() == "");
// Object parameter is added automatically.
REQUIRE(setter.GetParameters().size() == 0);
REQUIRE(setter.GetEvents().GetEventsCount() == 1);
REQUIRE(setter.GetEvents().GetEvent(0).GetType() ==
"BuiltinCommonInstructions::Standard");
auto &setterEvent =
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(0));
REQUIRE(setterEvent.GetConditions().size() == 0);
REQUIRE(setterEvent.GetActions().size() == 1);
auto &setterAction = setterEvent.GetActions().at(0);
REQUIRE(
setterAction.GetType() ==
"MyEventsExtension::MyEventsBasedObject::SetPropertyMovementAngle");
REQUIRE(setterAction.GetParametersCount() == 3);
REQUIRE(setterAction.GetParameter(0).GetPlainString() == "Object");
REQUIRE(setterAction.GetParameter(1).GetPlainString() == "=");
REQUIRE(setterAction.GetParameter(2).GetPlainString() ==
"GetArgumentAsNumber(\"Value\")");
}
}
SECTION("Can generate functions for a choice property in an object") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
auto &extension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &object = CreateObject(extension);
auto &property =
object.GetPropertyDescriptors().InsertNew("CollisionShape", 0);
property.SetType("Choice")
.SetLabel("Collision shape")
.SetLabel("Dot shape")
.SetDescription("The shape is used for collision.")
.SetGroup("Movement");
property.GetExtraInfo().push_back("Dot shape");
property.GetExtraInfo().push_back("Bounding disk");
gd::PropertyFunctionGenerator::GenerateObjectGetterAndSetter(
project, extension, object, property);
REQUIRE(
object.GetEventsFunctions().HasEventsFunctionNamed("CollisionShape"));
REQUIRE(object.GetEventsFunctions().HasEventsFunctionNamed(
"SetCollisionShape"));
auto &getter =
object.GetEventsFunctions().GetEventsFunction("CollisionShape");
REQUIRE(getter.GetFunctionType() ==
gd::EventsFunction::ExpressionAndCondition);
REQUIRE(getter.GetExpressionType().GetName() == "stringWithSelector");
REQUIRE(getter.GetExpressionType().GetExtraInfo() ==
"[\"Dot shape\",\"Bounding disk\"]");
}
SECTION("Can generate functions for a boolean property in an object") {
gd::Platform platform;
gd::Project project;
SetupProjectWithDummyPlatform(project, platform);
auto &extension =
project.InsertNewEventsFunctionsExtension("MyEventsExtension", 0);
auto &object = CreateObject(extension);
auto &property = object.GetPropertyDescriptors().InsertNew("Rotate", 0);
property.SetType("Boolean")
.SetLabel("Rotate object")
.SetDescription("The rotation follows movements done by this object.")
.SetGroup("Movement");
gd::PropertyFunctionGenerator::GenerateObjectGetterAndSetter(
project, extension, object, property);
REQUIRE(object.GetEventsFunctions().HasEventsFunctionNamed("Rotate"));
REQUIRE(object.GetEventsFunctions().HasEventsFunctionNamed("SetRotate"));
{
auto &getter = object.GetEventsFunctions().GetEventsFunction("Rotate");
REQUIRE(getter.GetFunctionType() == gd::EventsFunction::Condition);
REQUIRE(getter.GetExpressionType().GetName() == "boolean");
REQUIRE(getter.GetFullName() == "Rotate object");
REQUIRE(getter.GetGroup() ==
"My events based object movement configuration");
REQUIRE(getter.GetDescription() ==
"Check if rotate object. The rotation follows movements done by "
"this object.");
REQUIRE(getter.GetSentence() == "_PARAM0_ rotate object");
// The Object parameter is added automatically.
REQUIRE(getter.GetParameters().size() == 0);
REQUIRE(getter.GetEvents().GetEventsCount() == 1);
REQUIRE(getter.GetEvents().GetEvent(0).GetType() ==
"BuiltinCommonInstructions::Standard");
auto &getterEvent =
dynamic_cast<gd::StandardEvent &>(getter.GetEvents().GetEvent(0));
REQUIRE(getterEvent.GetConditions().size() == 1);
REQUIRE(getterEvent.GetActions().size() == 1);
auto &getterCondition = getterEvent.GetConditions().at(0);
REQUIRE(getterCondition.GetType() ==
"MyEventsExtension::MyEventsBasedObject::PropertyRotate");
REQUIRE(!getterCondition.IsInverted());
REQUIRE(getterCondition.GetParametersCount() == 1);
REQUIRE(getterCondition.GetParameter(0).GetPlainString() == "Object");
auto &getterAction = getterEvent.GetActions().at(0);
REQUIRE(getterAction.GetType() == "SetReturnBoolean");
REQUIRE(getterAction.GetParametersCount() == 1);
REQUIRE(getterAction.GetParameter(0).GetPlainString() == "True");
}
{
auto &setter = object.GetEventsFunctions().GetEventsFunction("SetRotate");
REQUIRE(setter.GetFunctionType() == gd::EventsFunction::Action);
REQUIRE(setter.GetFullName() == "Rotate object");
REQUIRE(setter.GetGroup() ==
"My events based object movement configuration");
REQUIRE(setter.GetDescription() ==
"Change if rotate object. The rotation follows movements done by "
"this object.");
REQUIRE(setter.GetSentence() == "_PARAM0_ rotate object: _PARAM1_");
// To generate the value parameter, the object parameter has to
// be declared too.
REQUIRE(setter.GetParameters().size() == 2);
auto &objectParameter = setter.GetParameters().at(0);
REQUIRE(objectParameter.GetName() == "Object");
REQUIRE(objectParameter.GetType() == "object");
REQUIRE(objectParameter.GetExtraInfo() ==
"MyEventsExtension::MyEventsBasedObject");
auto &valueParameter = setter.GetParameters().at(1);
REQUIRE(valueParameter.GetName() == "Value");
REQUIRE(valueParameter.GetType() == "yesorno");
REQUIRE(setter.GetEvents().GetEventsCount() == 2);
REQUIRE(setter.GetEvents().GetEvent(0).GetType() ==
"BuiltinCommonInstructions::Standard");
REQUIRE(setter.GetEvents().GetEvent(1).GetType() ==
"BuiltinCommonInstructions::Standard");
auto &setterNoEvent =
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(0));
REQUIRE(setterNoEvent.GetConditions().size() == 1);
REQUIRE(setterNoEvent.GetActions().size() == 1);
auto &setterNoCondition = setterNoEvent.GetConditions().at(0);
REQUIRE(setterNoCondition.GetType() == "GetArgumentAsBoolean");
REQUIRE(setterNoCondition.IsInverted());
REQUIRE(setterNoCondition.GetParametersCount() == 1);
REQUIRE(setterNoCondition.GetParameter(0).GetPlainString() ==
"\"Value\"");
auto &setterNoAction = setterNoEvent.GetActions().at(0);
REQUIRE(setterNoAction.GetType() ==
"MyEventsExtension::MyEventsBasedObject::SetPropertyRotate");
REQUIRE(setterNoAction.GetParametersCount() == 2);
REQUIRE(setterNoAction.GetParameter(0).GetPlainString() == "Object");
REQUIRE(setterNoAction.GetParameter(1).GetPlainString() == "no");
auto &setterYesEvent =
dynamic_cast<gd::StandardEvent &>(setter.GetEvents().GetEvent(1));
REQUIRE(setterYesEvent.GetConditions().size() == 1);
REQUIRE(setterYesEvent.GetActions().size() == 1);
auto &setterYesCondition = setterYesEvent.GetConditions().at(0);
REQUIRE(setterYesCondition.GetType() == "GetArgumentAsBoolean");
REQUIRE(!setterYesCondition.IsInverted());
REQUIRE(setterYesCondition.GetParametersCount() == 1);
REQUIRE(setterYesCondition.GetParameter(0).GetPlainString() ==
"\"Value\"");
auto &setterYesAction = setterYesEvent.GetActions().at(0);
REQUIRE(setterYesAction.GetType() ==
"MyEventsExtension::MyEventsBasedObject::SetPropertyRotate");
REQUIRE(setterYesAction.GetParametersCount() == 2);
REQUIRE(setterYesAction.GetParameter(0).GetPlainString() == "Object");
REQUIRE(setterYesAction.GetParameter(1).GetPlainString() == "yes");
}
}
SECTION("Can generate functions for a shared property") {
gd::Platform platform;
@@ -300,7 +553,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
.SetDescription("The angle of the trajectory direction.")
.SetGroup("Movement");
gd::PropertyFunctionGenerator::GenerateGetterAndSetter(
gd::PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
project, extension, behavior, property, true);
REQUIRE(
@@ -464,7 +717,7 @@ TEST_CASE("PropertyFunctionGenerator", "[common]") {
behavior.GetPropertyDescriptors().InsertNew("MovementAngle", 0);
property.SetType("Number");
gd::PropertyFunctionGenerator::GenerateGetterAndSetter(
gd::PropertyFunctionGenerator::GenerateBehaviorGetterAndSetter(
project, extension, behavior, property, false);
REQUIRE(

View File

@@ -2195,8 +2195,9 @@ interface WholeProjectRefactorer {
};
interface PropertyFunctionGenerator {
void STATIC_GenerateGetterAndSetter([Ref] Project project, [Ref] EventsFunctionsExtension extension, [Ref] EventsBasedBehavior eventsBasedBehavior, [Const, Ref] NamedPropertyDescriptor property, boolean isSharedProperties);
boolean STATIC_CanGenerateGetterAndSetter([Const, Ref] EventsBasedBehavior eventsBasedBehavior, [Const, Ref] NamedPropertyDescriptor property);
void STATIC_GenerateBehaviorGetterAndSetter([Ref] Project project, [Ref] EventsFunctionsExtension extension, [Ref] EventsBasedBehavior eventsBasedBehavior, [Const, Ref] NamedPropertyDescriptor property, boolean isSharedProperties);
void STATIC_GenerateObjectGetterAndSetter([Ref] Project project, [Ref] EventsFunctionsExtension extension, [Ref] EventsBasedObject eventsBasedObject, [Const, Ref] NamedPropertyDescriptor property);
boolean STATIC_CanGenerateGetterAndSetter([Const, Ref] AbstractEventsBasedEntity eventsBasedBehavior, [Const, Ref] NamedPropertyDescriptor property);
};
interface UsedExtensionsFinder {
@@ -2391,6 +2392,14 @@ interface EventsFunctionsContainer {
unsigned long GetEventsFunctionPosition([Const, Ref] EventsFunction eventsFunction);
};
interface AbstractEventsBasedEntity {
[Ref] EventsFunctionsContainer GetEventsFunctions();
[Ref] NamedPropertyDescriptorsList GetPropertyDescriptors();
void SerializeTo([Ref] SerializerElement element);
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
};
interface EventsBasedBehavior {
void EventsBasedBehavior();
@@ -2405,13 +2414,8 @@ interface EventsBasedBehavior {
[Ref] EventsBasedBehavior SetPrivate(boolean isPrivate);
boolean IsPrivate();
[Ref] EventsFunctionsContainer GetEventsFunctions();
[Ref] NamedPropertyDescriptorsList GetPropertyDescriptors();
[Ref] NamedPropertyDescriptorsList GetSharedPropertyDescriptors();
void SerializeTo([Ref] SerializerElement element);
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
[Const, Value] DOMString STATIC_GetPropertyActionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetPropertyConditionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetPropertyExpressionName([Const] DOMString propertyName);
@@ -2419,6 +2423,7 @@ interface EventsBasedBehavior {
[Const, Value] DOMString STATIC_GetSharedPropertyConditionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetSharedPropertyExpressionName([Const] DOMString propertyName);
};
EventsBasedBehavior implements AbstractEventsBasedEntity;
interface EventsBasedBehaviorsList {
[Ref] EventsBasedBehavior InsertNew([Const] DOMString name, unsigned long pos);
@@ -2447,17 +2452,26 @@ interface EventsBasedObject {
[Ref] EventsBasedObject SetDefaultName([Const] DOMString defaultName);
[Const, Ref] DOMString GetDefaultName();
[Ref] EventsFunctionsContainer GetEventsFunctions();
[Ref] NamedPropertyDescriptorsList GetPropertyDescriptors();
void SerializeTo([Ref] SerializerElement element);
void UnserializeFrom([Ref] Project project, [Const, Ref] SerializerElement element);
[Const, Value] DOMString STATIC_GetPropertyActionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetPropertyConditionName([Const] DOMString propertyName);
[Const, Value] DOMString STATIC_GetPropertyExpressionName([Const] DOMString propertyName);
// Inherited from gd::ObjectsContainer
[Ref] gdObject InsertNewObject([Ref] Project project, [Const] DOMString type, [Const] DOMString name, unsigned long pos);
[Ref] gdObject InsertObject([Const, Ref] gdObject obj, unsigned long pos);
boolean HasObjectNamed([Const] DOMString name);
[Ref] gdObject GetObject([Const] DOMString name);
[Ref] gdObject GetObjectAt(unsigned long pos);
unsigned long GetObjectPosition([Const] DOMString name);
void RemoveObject([Const] DOMString name);
void SwapObjects(unsigned long first, unsigned long second);
void MoveObject(unsigned long oldIndex, unsigned long newIndex);
void MoveObjectToAnotherContainer([Const] DOMString name, [Ref] ObjectsContainer newObjectsContainer, unsigned long newPosition);
unsigned long GetObjectsCount();
[Ref] ObjectGroupsContainer GetObjectGroups();
};
EventsBasedObject implements ObjectsContainer;
EventsBasedObject implements AbstractEventsBasedEntity;
interface EventsBasedObjectsList {
[Ref] EventsBasedObject InsertNew([Const] DOMString name, unsigned long pos);

View File

@@ -600,7 +600,8 @@ typedef ExtensionAndMetadata<ExpressionMetadata> ExtensionAndExpressionMetadata;
GetBehaviorsWithType
#define STATIC_FixInvalidRequiredBehaviorProperties \
FixInvalidRequiredBehaviorProperties
#define STATIC_GenerateGetterAndSetter GenerateGetterAndSetter
#define STATIC_GenerateBehaviorGetterAndSetter GenerateBehaviorGetterAndSetter
#define STATIC_GenerateObjectGetterAndSetter GenerateObjectGetterAndSetter
#define STATIC_CanGenerateGetterAndSetter CanGenerateGetterAndSetter
#define STATIC_CreateRectangle CreateRectangle
#define STATIC_SanityCheckBehaviorProperty SanityCheckBehaviorProperty

View File

@@ -0,0 +1,9 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdAbstractEventsBasedEntity {
getEventsFunctions(): gdEventsFunctionsContainer;
getPropertyDescriptors(): gdNamedPropertyDescriptorsList;
serializeTo(element: gdSerializerElement): void;
unserializeFrom(project: gdProject, element: gdSerializerElement): void;
delete(): void;
ptr: number;
};

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdEventsBasedBehavior {
declare class gdEventsBasedBehavior extends gdAbstractEventsBasedEntity {
constructor(): void;
setDescription(description: string): gdEventsBasedBehavior;
getDescription(): string;
@@ -11,11 +11,7 @@ declare class gdEventsBasedBehavior {
getObjectType(): string;
setPrivate(isPrivate: boolean): gdEventsBasedBehavior;
isPrivate(): boolean;
getEventsFunctions(): gdEventsFunctionsContainer;
getPropertyDescriptors(): gdNamedPropertyDescriptorsList;
getSharedPropertyDescriptors(): gdNamedPropertyDescriptorsList;
serializeTo(element: gdSerializerElement): void;
unserializeFrom(project: gdProject, element: gdSerializerElement): void;
static getPropertyActionName(propertyName: string): string;
static getPropertyConditionName(propertyName: string): string;
static getPropertyExpressionName(propertyName: string): string;

View File

@@ -1,5 +1,5 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdEventsBasedObject extends gdObjectsContainer {
declare class gdEventsBasedObject extends gdAbstractEventsBasedEntity {
constructor(): void;
setDescription(description: string): gdEventsBasedObject;
getDescription(): string;
@@ -9,13 +9,21 @@ declare class gdEventsBasedObject extends gdObjectsContainer {
getFullName(): string;
setDefaultName(defaultName: string): gdEventsBasedObject;
getDefaultName(): string;
getEventsFunctions(): gdEventsFunctionsContainer;
getPropertyDescriptors(): gdNamedPropertyDescriptorsList;
serializeTo(element: gdSerializerElement): void;
unserializeFrom(project: gdProject, element: gdSerializerElement): void;
static getPropertyActionName(propertyName: string): string;
static getPropertyConditionName(propertyName: string): string;
static getPropertyExpressionName(propertyName: string): string;
insertNewObject(project: gdProject, type: string, name: string, pos: number): gdObject;
insertObject(obj: gdObject, pos: number): gdObject;
hasObjectNamed(name: string): boolean;
getObject(name: string): gdObject;
getObjectAt(pos: number): gdObject;
getObjectPosition(name: string): number;
removeObject(name: string): void;
swapObjects(first: number, second: number): void;
moveObject(oldIndex: number, newIndex: number): void;
moveObjectToAnotherContainer(name: string, newObjectsContainer: gdObjectsContainer, newPosition: number): void;
getObjectsCount(): number;
getObjectGroups(): gdObjectGroupsContainer;
delete(): void;
ptr: number;
};

View File

@@ -1,7 +1,8 @@
// Automatically generated by GDevelop.js/scripts/generate-types.js
declare class gdPropertyFunctionGenerator {
static generateGetterAndSetter(project: gdProject, extension: gdEventsFunctionsExtension, eventsBasedBehavior: gdEventsBasedBehavior, property: gdNamedPropertyDescriptor, isSharedProperties: boolean): void;
static canGenerateGetterAndSetter(eventsBasedBehavior: gdEventsBasedBehavior, property: gdNamedPropertyDescriptor): boolean;
static generateBehaviorGetterAndSetter(project: gdProject, extension: gdEventsFunctionsExtension, eventsBasedBehavior: gdEventsBasedBehavior, property: gdNamedPropertyDescriptor, isSharedProperties: boolean): void;
static generateObjectGetterAndSetter(project: gdProject, extension: gdEventsFunctionsExtension, eventsBasedObject: gdEventsBasedObject, property: gdNamedPropertyDescriptor): void;
static canGenerateGetterAndSetter(eventsBasedBehavior: gdAbstractEventsBasedEntity, property: gdNamedPropertyDescriptor): boolean;
delete(): void;
ptr: number;
};

View File

@@ -172,6 +172,7 @@ declare class libGDevelop {
EventsFunction_FunctionType: Class<EventsFunction_FunctionType>;
EventsFunction: Class<gdEventsFunction>;
EventsFunctionsContainer: Class<gdEventsFunctionsContainer>;
AbstractEventsBasedEntity: Class<gdAbstractEventsBasedEntity>;
EventsBasedBehavior: Class<gdEventsBasedBehavior>;
EventsBasedBehaviorsList: Class<gdEventsBasedBehaviorsList>;
EventsBasedObject: Class<gdEventsBasedObject>;

View File

@@ -230,7 +230,7 @@ export default class EventsBasedBehaviorPropertiesEditor extends React.Component
{
label: i18n._(t`Generate expression and action`),
click: () =>
gd.PropertyFunctionGenerator.generateGetterAndSetter(
gd.PropertyFunctionGenerator.generateBehaviorGetterAndSetter(
this.props.project,
this.props.extension,
this.props.eventsBasedBehavior,

View File

@@ -61,6 +61,7 @@ export default class EventBasedObjectChildrenEditor extends React.Component<
project,
eventsBasedObject,
globalObjectsContainer,
// $FlowFixMe gdObjectsContainer should be a member of gdEventsBasedObject instead of a base class.
eventsBasedObject,
object.getName(),
/* isObjectGroup=*/ false,
@@ -208,6 +209,7 @@ export default class EventBasedObjectChildrenEditor extends React.Component<
ObjectsRenderingService
)}
project={project}
// $FlowFixMe gdObjectsContainer should be a member of gdEventsBasedObject instead of a base class.
objectsContainer={eventsBasedObject}
layout={null}
// TODO EBO Allow to use project resources as place holders

View File

@@ -75,6 +75,7 @@ export default function EventsBasedObjectEditorDialog({
{currentTab === 'properties' && (
<EventsBasedObjectPropertiesEditor
project={project}
extension={eventsFunctionsExtension}
eventsBasedObject={eventsBasedObject}
onRenameProperty={onRenameProperty}
/>

View File

@@ -30,6 +30,7 @@ const gd: libGDevelop = global.gd;
type Props = {|
project: gdProject,
extension: gdEventsFunctionsExtension,
eventsBasedObject: gdEventsBasedObject,
onPropertiesUpdated?: () => void,
onRenameProperty: (oldName: string, newName: string) => void,
@@ -231,6 +232,20 @@ export default class EventsBasedObjectPropertiesEditor extends React.Component<
click: () => this._moveProperty(i, i + 1),
enabled: i + 1 < properties.getCount(),
},
{
label: i18n._(t`Generate expression and action`),
click: () =>
gd.PropertyFunctionGenerator.generateObjectGetterAndSetter(
this.props.project,
this.props.extension,
this.props.eventsBasedObject,
property
),
enabled: gd.PropertyFunctionGenerator.canGenerateGetterAndSetter(
this.props.eventsBasedObject,
property
),
},
]}
/>
</MiniToolbar>