mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
243 Commits
v5.3.201
...
experiment
Author | SHA1 | Date | |
---|---|---|---|
![]() |
5eb5fb3af9 | ||
![]() |
cd80872fca | ||
![]() |
61cb6dde0e | ||
![]() |
29c8de0987 | ||
![]() |
802e9a5128 | ||
![]() |
c82602919b | ||
![]() |
80cbb8f542 | ||
![]() |
a9ceba7bef | ||
![]() |
7d9e72c876 | ||
![]() |
3baf5903d3 | ||
![]() |
6008e1045d | ||
![]() |
9dda9a89c5 | ||
![]() |
814c6aec4f | ||
![]() |
84e4158407 | ||
![]() |
aa6c3bc1c8 | ||
![]() |
41dc6d0966 | ||
![]() |
9c19865dec | ||
![]() |
bbfb7f63f0 | ||
![]() |
2f8304c2dd | ||
![]() |
c1aa88861d | ||
![]() |
254ab0350b | ||
![]() |
b0a3c34803 | ||
![]() |
63a3265310 | ||
![]() |
d19292f43d | ||
![]() |
3646d05b65 | ||
![]() |
25a4d04896 | ||
![]() |
2df6c13ed7 | ||
![]() |
93f84a14cb | ||
![]() |
02e0ebf63b | ||
![]() |
da3abb331a | ||
![]() |
a5a9524ed6 | ||
![]() |
c9cc1f6fdc | ||
![]() |
de140f1190 | ||
![]() |
9a82fda7fe | ||
![]() |
eac92704fa | ||
![]() |
dc607d85c3 | ||
![]() |
e96269d899 | ||
![]() |
05d622c5c0 | ||
![]() |
0758397196 | ||
![]() |
65293ddd99 | ||
![]() |
225a3a67c6 | ||
![]() |
a96171aacd | ||
![]() |
1a21a0bfb3 | ||
![]() |
cc23301875 | ||
![]() |
aa513c04e6 | ||
![]() |
a4e8e8c00b | ||
![]() |
0d34680fcd | ||
![]() |
4abdb9dca6 | ||
![]() |
db05a07023 | ||
![]() |
78ebe58713 | ||
![]() |
420c7a4429 | ||
![]() |
1442a2772e | ||
![]() |
ce18bdd5a7 | ||
![]() |
2f2cc1bbe3 | ||
![]() |
097ad4fff5 | ||
![]() |
2112ed789a | ||
![]() |
a41a1c14a0 | ||
![]() |
771d3264bb | ||
![]() |
9fa1e552e0 | ||
![]() |
503a0873d9 | ||
![]() |
715480bdef | ||
![]() |
869fd7eb08 | ||
![]() |
e0cb8e4953 | ||
![]() |
0ef4953241 | ||
![]() |
d154384164 | ||
![]() |
504df2e0a3 | ||
![]() |
e9adaa94c5 | ||
![]() |
35da31c5c5 | ||
![]() |
e65492e1a1 | ||
![]() |
44827ea372 | ||
![]() |
ab3ffe6785 | ||
![]() |
d83d049ac9 | ||
![]() |
67a7bd7af2 | ||
![]() |
6db5267878 | ||
![]() |
a51c223c9c | ||
![]() |
0a4e5a1012 | ||
![]() |
acce714736 | ||
![]() |
3c34a8806b | ||
![]() |
1d4cb7bef0 | ||
![]() |
7badacd24a | ||
![]() |
11ab92fc0e | ||
![]() |
ddb1e335bc | ||
![]() |
8d035a774d | ||
![]() |
5b1e3565d3 | ||
![]() |
8c88038bfb | ||
![]() |
f62811974d | ||
![]() |
b516037d2b | ||
![]() |
98befc8000 | ||
![]() |
377231fb37 | ||
![]() |
22ae8ac489 | ||
![]() |
40674fd3b9 | ||
![]() |
0792e59b24 | ||
![]() |
8ba6ad7b43 | ||
![]() |
84b07bc84d | ||
![]() |
c46d39cbed | ||
![]() |
b96132964c | ||
![]() |
130cd1e3a7 | ||
![]() |
fbbcf25bf5 | ||
![]() |
ffaae4d3d4 | ||
![]() |
75d79a7758 | ||
![]() |
d91fb78848 | ||
![]() |
e0a2ed1654 | ||
![]() |
d5f2be1c19 | ||
![]() |
7abcfe8af2 | ||
![]() |
b86dd9efce | ||
![]() |
15f6b62c5b | ||
![]() |
eb995ec7c7 | ||
![]() |
a076571120 | ||
![]() |
ec9cb790e7 | ||
![]() |
4a283add00 | ||
![]() |
6b3faa42bb | ||
![]() |
555ee61e63 | ||
![]() |
b838c8549b | ||
![]() |
33db6ee359 | ||
![]() |
f361d3e1fa | ||
![]() |
441401f34c | ||
![]() |
558daa2075 | ||
![]() |
cd475316df | ||
![]() |
8b21e72c85 | ||
![]() |
a9d6f18c11 | ||
![]() |
f58e1113b6 | ||
![]() |
f82b5fc66d | ||
![]() |
2f19a9bb33 | ||
![]() |
8f739d85c2 | ||
![]() |
f23847617d | ||
![]() |
876332a782 | ||
![]() |
93c74c9fd6 | ||
![]() |
e92d8496ac | ||
![]() |
35e67a6d26 | ||
![]() |
740c7ae8bc | ||
![]() |
432a91c47b | ||
![]() |
799bc762aa | ||
![]() |
147a0eed53 | ||
![]() |
920e1d423f | ||
![]() |
c013f319ee | ||
![]() |
db53e84c6f | ||
![]() |
4b85f710a9 | ||
![]() |
07a350dadd | ||
![]() |
7ccbf91973 | ||
![]() |
410fecf715 | ||
![]() |
967bf5cbe3 | ||
![]() |
0020f72850 | ||
![]() |
0eb7b85e77 | ||
![]() |
063bf51783 | ||
![]() |
482fb3b85e | ||
![]() |
9a4a84d2af | ||
![]() |
9a705b98e2 | ||
![]() |
da940abdc2 | ||
![]() |
528b8f4e6c | ||
![]() |
7212d56a1b | ||
![]() |
5cba43335c | ||
![]() |
324698e269 | ||
![]() |
d219bf05d3 | ||
![]() |
9cbc421d74 | ||
![]() |
f63d9d1b5c | ||
![]() |
dd5d0669b1 | ||
![]() |
e681632e60 | ||
![]() |
0bcb219e00 | ||
![]() |
6d5e9c1676 | ||
![]() |
5ded5648bf | ||
![]() |
687f926bc5 | ||
![]() |
4a2d573956 | ||
![]() |
ce77414f85 | ||
![]() |
298ff6311d | ||
![]() |
ca0a000ae1 | ||
![]() |
dc87f138a6 | ||
![]() |
28af860aff | ||
![]() |
4dbc607314 | ||
![]() |
bfefe9baf4 | ||
![]() |
2332359c19 | ||
![]() |
68b6c443c3 | ||
![]() |
37e113baaa | ||
![]() |
a8a8c142a3 | ||
![]() |
012e625a47 | ||
![]() |
c0e6d98e4c | ||
![]() |
ab63e02862 | ||
![]() |
1b13127a2f | ||
![]() |
3de0861172 | ||
![]() |
795417c915 | ||
![]() |
e8540dd720 | ||
![]() |
3c5fee0535 | ||
![]() |
7f2806bd89 | ||
![]() |
886fdb464e | ||
![]() |
6aaeda6c49 | ||
![]() |
830e35b368 | ||
![]() |
fa4a621888 | ||
![]() |
8756932c12 | ||
![]() |
0b5f929773 | ||
![]() |
183fba4720 | ||
![]() |
9d608a0e93 | ||
![]() |
5bbfd81d89 | ||
![]() |
a441bb04ef | ||
![]() |
ccf5e390d6 | ||
![]() |
e633aa77c2 | ||
![]() |
12275d0814 | ||
![]() |
4ed1889856 | ||
![]() |
ae6ac2068b | ||
![]() |
a31c5cfac3 | ||
![]() |
1917d5aedd | ||
![]() |
d0c85cd3bc | ||
![]() |
afed90ccef | ||
![]() |
ff9c6e5cf3 | ||
![]() |
199d315e29 | ||
![]() |
ddf426c2fd | ||
![]() |
43648b0a18 | ||
![]() |
96e5d6966a | ||
![]() |
eb256b3412 | ||
![]() |
d89bfd27f8 | ||
![]() |
7cef3b3a41 | ||
![]() |
f3a87a2159 | ||
![]() |
4df91f3e77 | ||
![]() |
8ca82ef457 | ||
![]() |
0c3719ff0c | ||
![]() |
a76ba988b2 | ||
![]() |
8f002541ef | ||
![]() |
6fd82376a8 | ||
![]() |
db2d6f90a3 | ||
![]() |
f32180d923 | ||
![]() |
4886cf4fd3 | ||
![]() |
0fd25c381a | ||
![]() |
916e642465 | ||
![]() |
eaebc16f49 | ||
![]() |
231d92a2fa | ||
![]() |
e3cc01e902 | ||
![]() |
fe68286eaf | ||
![]() |
7d95e44b51 | ||
![]() |
9b448f1ddf | ||
![]() |
8f34a100e5 | ||
![]() |
cc3a9af8ce | ||
![]() |
75bfa5cb45 | ||
![]() |
5ac8f411fe | ||
![]() |
870247a3df | ||
![]() |
80b68d3bb5 | ||
![]() |
6e8a8d6868 | ||
![]() |
2310f2a618 | ||
![]() |
f8bd3fca00 | ||
![]() |
92b9203ce8 | ||
![]() |
4ca859c8b9 | ||
![]() |
701b5a3250 | ||
![]() |
1e87b74d48 | ||
![]() |
b7a4bab53c | ||
![]() |
2223b6516b | ||
![]() |
7d89208e7b |
@@ -11,13 +11,24 @@
|
||||
version: 2.1
|
||||
orbs:
|
||||
aws-cli: circleci/aws-cli@2.0.6
|
||||
macos: circleci/macos@2.5.1 # For Rosetta (see below)
|
||||
node: circleci/node@5.2.0 # For a recent npm version (see below)
|
||||
jobs:
|
||||
# Build the **entire** app for macOS.
|
||||
build-macos:
|
||||
macos:
|
||||
xcode: 14.2.0
|
||||
resource_class: macos.m1.large.gen1
|
||||
steps:
|
||||
- checkout
|
||||
# Install Rosetta for AWS CLI and disable TSO to speed up S3 uploads (https://support.circleci.com/hc/en-us/articles/19334402064027-Troubleshooting-slow-uploads-to-S3-for-jobs-using-an-m1-macOS-resource-class)
|
||||
- macos/install-rosetta
|
||||
- run: sudo sysctl net.inet.tcp.tso=0
|
||||
|
||||
# Install a recent version of npm to workaround a notarization issue because of a symlink made by npm: https://github.com/electron-userland/electron-builder/issues/7755
|
||||
# Node.js v20.14.0 comes with npm v10.7.0.
|
||||
- node/install:
|
||||
node-version: "20.14.0"
|
||||
|
||||
# System dependencies (for Emscripten and upload)
|
||||
- run:
|
||||
|
3
.gitattributes
vendored
3
.gitattributes
vendored
@@ -1,12 +1,11 @@
|
||||
Core/GDCore/Serialization/rapidjson/rapidjson.h/* linguist-vendored
|
||||
Core/GDCore/TinyXml/* linguist-vendored
|
||||
Extensions/ParticleSystem/SPARK/* linguist-vendored
|
||||
Extensions/PhysicsBehavior/Box2D/* linguist-vendored
|
||||
Extensions/PhysicsBehavior/box2djs/* linguist-vendored
|
||||
Extensions/Physics2Behavior/box2d.js linguist-vendored
|
||||
Extensions/BBText/pixi-multistyle-text/* linguist-vendored
|
||||
Extensions/P2P/A_peer.js linguist-vendored
|
||||
Extensions/Multiplayer/peer.js linguist-vendored
|
||||
Extensions/Shopify/shopify-buy.umd.polyfilled.min.js linguist-vendored
|
||||
Extensions/TileMap/pako/* linguist-vendored
|
||||
Extensions/TileMap/pixi-tilemap/* linguist-vendored
|
||||
Extensions/TweenBehavior/shifty.js linguist-vendored
|
||||
|
35
.travis.yml
35
.travis.yml
@@ -17,11 +17,11 @@ cache:
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
# Build dependencies:
|
||||
- cmake
|
||||
- p7zip-full
|
||||
# Build dependencies:
|
||||
- cmake
|
||||
- p7zip-full
|
||||
|
||||
before_install:
|
||||
# This workaround is required to avoid libstdc++ errors (Emscripten requires a recent version of libstdc++)
|
||||
@@ -29,47 +29,48 @@ before_install:
|
||||
- sudo dpkg --force-all -i libstdc++6
|
||||
|
||||
install:
|
||||
# Ensure we use a recent version of Node.js (and npm).
|
||||
# Ensure we use a recent version of Node.js (and npm).
|
||||
- nvm install v16 && nvm use v16
|
||||
#Compile the tests only for GDCore
|
||||
#Compile the tests only for GDCore
|
||||
- mkdir .build-tests
|
||||
- cd .build-tests
|
||||
- cmake -DBUILD_GDJS=FALSE -DBUILD_TESTS=TRUE -DCMAKE_CXX_COMPILER=$(which $CXX) -DCMAKE_C_COMPILER=$(which $CC) ..
|
||||
- make -j 4
|
||||
- cd ..
|
||||
# Install Emscripten (for GDevelop.js)
|
||||
- git clone https://github.com/juj/emsdk.git
|
||||
# Install Emscripten (for GDevelop.js)
|
||||
# Specify the tag for the core repository to avois breaking changes.
|
||||
- git clone --depth 1 --branch 3.1.21 https://github.com/juj/emsdk.git
|
||||
- cd emsdk && ./emsdk install 3.1.21 && ./emsdk activate 3.1.21 && cd ..
|
||||
# Install GDevelop.js dependencies
|
||||
# Install GDevelop.js dependencies
|
||||
- cd GDevelop.js && npm install && cd ..
|
||||
# Build GDevelop.js
|
||||
# (in a subshell to avoid Emscripten polluting the Node.js and npm version for the rest of the build)
|
||||
# Build GDevelop.js
|
||||
# (in a subshell to avoid Emscripten polluting the Node.js and npm version for the rest of the build)
|
||||
- (set -e; cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build && cd ..)
|
||||
# Install newIDE tests dependencies
|
||||
# Install newIDE tests dependencies
|
||||
- npm -v
|
||||
- cd newIDE/app && npm install
|
||||
- cd ../..
|
||||
# Install GDJS tests dependencies
|
||||
# Install GDJS tests dependencies
|
||||
- cd GDJS && npm install && cd tests && npm install
|
||||
- cd ../..
|
||||
|
||||
script:
|
||||
# GDCore tests:
|
||||
# GDCore tests:
|
||||
- cd .build-tests
|
||||
- Core/GDCore_tests
|
||||
- cd ..
|
||||
# GDevelop.js tests
|
||||
# GDevelop.js tests
|
||||
- cd GDevelop.js
|
||||
- npm test
|
||||
- cd ..
|
||||
# newIDE tests:
|
||||
# newIDE tests:
|
||||
- cd newIDE/app
|
||||
- npm test
|
||||
- npm run flow
|
||||
- npm run check-format
|
||||
- npm run check-script-types
|
||||
- cd ../..
|
||||
# GDJS tests:
|
||||
# GDJS tests:
|
||||
- cd GDJS
|
||||
- npm run check-format
|
||||
- cd ..
|
||||
|
@@ -58,99 +58,7 @@
|
||||
* Common functions and tools for programming.
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup TinyXml Integrated TinyXml library
|
||||
*
|
||||
* See the full documentation of TinyXml [here](http://www.grinninglizard.com/tinyxmldocs/index.html).
|
||||
*/
|
||||
|
||||
/**
|
||||
* \defgroup SpriteObjectExtension Standard Sprite Object extension
|
||||
* \ingroup BuiltinExtensions
|
||||
*/
|
||||
|
||||
/**
|
||||
* \class TiXmlAttribute
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlAttributeSet
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlBase
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlComment
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlCursor
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlDeclaration
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlDocument
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlElement
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlHandle
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlNode
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlOutStream
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlParsingData
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlPrinter
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlString
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlText
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlUnknown
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
/**
|
||||
* \class TiXmlVisitor
|
||||
* \brief Part of the tinyxml library
|
||||
* \ingroup TinyXml
|
||||
*/
|
||||
*/
|
@@ -49,7 +49,8 @@ vector<pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
ForEachChildVariableEvent::GetAllExpressionsWithMetadata() {
|
||||
vector<pair<gd::Expression*, gd::ParameterMetadata> >
|
||||
allExpressionsWithMetadata;
|
||||
auto metadata = gd::ParameterMetadata().SetType("scenevar");
|
||||
auto metadata = gd::ParameterMetadata().SetType("variable");
|
||||
metadata.SetExtraInfo("AllowUndeclaredVariable");
|
||||
allExpressionsWithMetadata.push_back(
|
||||
std::make_pair(&iterableVariableName, metadata));
|
||||
allExpressionsWithMetadata.push_back(
|
||||
@@ -63,7 +64,8 @@ vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
ForEachChildVariableEvent::GetAllExpressionsWithMetadata() const {
|
||||
vector<pair<const gd::Expression*, const gd::ParameterMetadata> >
|
||||
allExpressionsWithMetadata;
|
||||
auto metadata = gd::ParameterMetadata().SetType("scenevar");
|
||||
auto metadata = gd::ParameterMetadata().SetType("variable");
|
||||
metadata.SetExtraInfo("AllowUndeclaredVariable");
|
||||
allExpressionsWithMetadata.push_back(
|
||||
std::make_pair(&iterableVariableName, metadata));
|
||||
allExpressionsWithMetadata.push_back(
|
||||
|
@@ -8,7 +8,6 @@
|
||||
#include "GDCore/Events/Serialization.h"
|
||||
#include "GDCore/Events/Tools/EventsCodeNameMangler.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/TinyXml/tinyxml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@@ -10,7 +10,6 @@
|
||||
#include "GDCore/Events/CodeGeneration/EventsCodeGenerator.h"
|
||||
#include "GDCore/Events/Serialization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/TinyXml/tinyxml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@@ -4,8 +4,8 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_REPEATEVENT_H
|
||||
#define GDCORE_REPEATEVENT_H
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
namespace gd {
|
||||
@@ -36,10 +36,10 @@ class GD_CORE_API RepeatEvent : public gd::BaseEvent {
|
||||
const gd::InstructionsList& GetActions() const { return actions; };
|
||||
gd::InstructionsList& GetActions() { return actions; };
|
||||
|
||||
const gd::String& GetRepeatExpression() const {
|
||||
return repeatNumberExpression.GetPlainString();
|
||||
const gd::Expression& GetRepeatExpression() const {
|
||||
return repeatNumberExpression;
|
||||
};
|
||||
void SetRepeatExpression(gd::String repeatNumberExpression_) {
|
||||
void SetRepeatExpressionPlainString(gd::String repeatNumberExpression_) {
|
||||
repeatNumberExpression = gd::Expression(repeatNumberExpression_);
|
||||
};
|
||||
|
||||
@@ -68,5 +68,3 @@ class GD_CORE_API RepeatEvent : public gd::BaseEvent {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_REPEATEVENT_H
|
||||
|
@@ -15,7 +15,8 @@ using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
StandardEvent::StandardEvent() : BaseEvent() {}
|
||||
StandardEvent::StandardEvent()
|
||||
: BaseEvent(), variables(gd::VariablesContainer::SourceType::Local) {}
|
||||
|
||||
StandardEvent::~StandardEvent(){};
|
||||
|
||||
@@ -57,6 +58,9 @@ void StandardEvent::SerializeTo(SerializerElement& element) const {
|
||||
if (!events.IsEmpty())
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
if (HasVariables()) {
|
||||
variables.SerializeTo(element.AddChild("variables"));
|
||||
}
|
||||
}
|
||||
|
||||
void StandardEvent::UnserializeFrom(gd::Project& project,
|
||||
@@ -71,6 +75,11 @@ void StandardEvent::UnserializeFrom(gd::Project& project,
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
|
||||
variables.Clear();
|
||||
if (element.HasChild("variables")) {
|
||||
variables.UnserializeFrom(element.GetChild("variables"));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -4,13 +4,13 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef GDCORE_STANDARDEVENT_H
|
||||
#define GDCORE_STANDARDEVENT_H
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Events/InstructionsList.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class Project;
|
||||
@@ -33,6 +33,10 @@ class GD_CORE_API StandardEvent : public gd::BaseEvent {
|
||||
virtual const gd::EventsList& GetSubEvents() const { return events; };
|
||||
virtual gd::EventsList& GetSubEvents() { return events; };
|
||||
|
||||
virtual bool CanHaveVariables() const { return true; }
|
||||
virtual const gd::VariablesContainer& GetVariables() const { return variables; };
|
||||
virtual gd::VariablesContainer& GetVariables() { return variables; };
|
||||
|
||||
const gd::InstructionsList& GetConditions() const { return conditions; };
|
||||
gd::InstructionsList& GetConditions() { return conditions; };
|
||||
|
||||
@@ -53,9 +57,7 @@ class GD_CORE_API StandardEvent : public gd::BaseEvent {
|
||||
gd::InstructionsList conditions;
|
||||
gd::InstructionsList actions;
|
||||
EventsList events;
|
||||
VariablesContainer variables;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_STANDARDEVENT_H
|
||||
#endif
|
||||
|
117
Core/GDCore/Events/CodeGeneration/DiagnosticReport.h
Normal file
117
Core/GDCore/Events/CodeGeneration/DiagnosticReport.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API ProjectDiagnostic {
|
||||
public:
|
||||
enum ErrorType {
|
||||
UndeclaredVariable,
|
||||
MissingBehavior,
|
||||
UnknownObject,
|
||||
MismatchedObjectType,
|
||||
};
|
||||
|
||||
ProjectDiagnostic(ErrorType type_, const gd::String &message_,
|
||||
const gd::String &actualValue_,
|
||||
const gd::String &expectedValue_, const gd::String &objectName_ = "")
|
||||
: type(type_), message(message_), actualValue(actualValue_), expectedValue(expectedValue_),
|
||||
objectName(objectName_){};
|
||||
virtual ~ProjectDiagnostic(){};
|
||||
|
||||
ErrorType GetType() const { return type; };
|
||||
const gd::String &GetMessage() const { return message; }
|
||||
const gd::String &GetObjectName() const { return objectName; }
|
||||
const gd::String &GetActualValue() const { return actualValue; }
|
||||
const gd::String &GetExpectedValue() const { return expectedValue; }
|
||||
|
||||
private:
|
||||
ErrorType type;
|
||||
gd::String message;
|
||||
gd::String objectName;
|
||||
gd::String actualValue;
|
||||
gd::String expectedValue;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API DiagnosticReport {
|
||||
public:
|
||||
DiagnosticReport(){};
|
||||
virtual ~DiagnosticReport(){};
|
||||
|
||||
void Add(const gd::ProjectDiagnostic &projectDiagnostic) {
|
||||
projectDiagnostics.push_back(
|
||||
gd::make_unique<gd::ProjectDiagnostic>(projectDiagnostic));
|
||||
};
|
||||
|
||||
const ProjectDiagnostic &Get(std::size_t index) const {
|
||||
return *projectDiagnostics[index].get();
|
||||
};
|
||||
|
||||
std::size_t Count() const { return projectDiagnostics.size(); };
|
||||
|
||||
const gd::String &GetSceneName() const { return sceneName; }
|
||||
|
||||
void SetSceneName(const gd::String &sceneName_) {
|
||||
sceneName = sceneName_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<gd::ProjectDiagnostic>> projectDiagnostics;
|
||||
gd::String sceneName;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API WholeProjectDiagnosticReport {
|
||||
public:
|
||||
WholeProjectDiagnosticReport(){};
|
||||
virtual ~WholeProjectDiagnosticReport(){};
|
||||
|
||||
const DiagnosticReport &Get(std::size_t index) const {
|
||||
return *diagnosticReports[index].get();
|
||||
};
|
||||
|
||||
void Clear() {
|
||||
diagnosticReports.clear();
|
||||
};
|
||||
|
||||
DiagnosticReport& AddNewDiagnosticReportForScene(const gd::String &sceneName) {
|
||||
auto diagnosticReport = gd::make_unique<gd::DiagnosticReport>();
|
||||
diagnosticReport->SetSceneName(sceneName);
|
||||
diagnosticReports.push_back(std::move(diagnosticReport));
|
||||
return *diagnosticReports[diagnosticReports.size() - 1].get();
|
||||
};
|
||||
|
||||
std::size_t Count() const { return diagnosticReports.size(); };
|
||||
|
||||
bool HasAnyIssue() {
|
||||
for (auto& diagnosticReport : diagnosticReports) {
|
||||
if (diagnosticReport->Count() > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<gd::DiagnosticReport>> diagnosticReports;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -15,6 +15,7 @@
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/IDE/ProjectBrowserHelper.h"
|
||||
|
||||
namespace gd {
|
||||
@@ -47,6 +48,9 @@ void EffectsCodeGenerator::GenerateEffectsIncludeFiles(
|
||||
|
||||
// TODO Merge with UsedExtensionsFinder.
|
||||
|
||||
// TODO Factorize with the iteration on all effects for resource exposure.
|
||||
// TODO Implement an ArbitraryEffectWorker and add a method in ProjectBrowserHelper
|
||||
|
||||
// See also gd::Project::ExposeResources for a method that traverse the whole
|
||||
// project (this time for resources) and
|
||||
// WholeProjectRefactorer::ExposeProjectEvents.
|
||||
@@ -68,6 +72,27 @@ void EffectsCodeGenerator::GenerateEffectsIncludeFiles(
|
||||
|
||||
// Add objects effects
|
||||
gd::ProjectBrowserHelper::ExposeProjectObjects(project, effectsCodeGenerator);
|
||||
|
||||
// Add event-based objects layouts effects
|
||||
for (std::size_t s = 0; s < project.GetEventsFunctionsExtensionsCount();
|
||||
s++) {
|
||||
auto &eventsFunctionExtension = project.GetEventsFunctionsExtension(s);
|
||||
|
||||
auto &eventsBasedObjects = eventsFunctionExtension.GetEventsBasedObjects();
|
||||
for (std::size_t objectIndex = 0;
|
||||
objectIndex < eventsBasedObjects.GetCount(); ++objectIndex) {
|
||||
auto &eventsBasedObject = eventsBasedObjects.Get(objectIndex);
|
||||
|
||||
auto &layers = eventsBasedObject.GetLayers();
|
||||
for (std::size_t l = 0; l < layers.GetLayersCount(); ++l) {
|
||||
auto &effects = layers.GetLayer(l).GetEffects();
|
||||
for (std::size_t e = 0; e < effects.GetEffectsCount(); ++e) {
|
||||
auto &effect = effects.GetEffect(e);
|
||||
effectsCodeGenerator.AddEffectIncludeFiles(effect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef EVENTSCODEGENERATIONCONTEXT_H
|
||||
#define EVENTSCODEGENERATIONCONTEXT_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@@ -325,4 +325,3 @@ class GD_CORE_API EventsCodeGenerationContext {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
#endif // EVENTSCODEGENERATIONCONTEXT_H
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableNameFinder.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/ObjectsContainersList.h"
|
||||
@@ -254,12 +255,12 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
|
||||
}
|
||||
|
||||
gd::String operatorStr = arguments[operatorIndex];
|
||||
if (operatorStr.size() > 2)
|
||||
if (operatorStr.size() > 2 && operatorStr[0] == '\"') {
|
||||
operatorStr = operatorStr.substr(
|
||||
1,
|
||||
operatorStr.length() - 1 -
|
||||
1); // Operator contains quote which must be removed.
|
||||
|
||||
}
|
||||
auto mutators = instrInfos.codeExtraInformation.optionalMutators;
|
||||
auto mutator = mutators.find(operatorStr);
|
||||
if (mutator == mutators.end()) {
|
||||
@@ -279,6 +280,9 @@ gd::String EventsCodeGenerator::GenerateMutatorCall(
|
||||
argumentsStr += arguments[i];
|
||||
}
|
||||
}
|
||||
if (instrInfos.GetManipulatedType() == "boolean") {
|
||||
return callStartString + "(" + argumentsStr + ")." + mutator->second;
|
||||
}
|
||||
|
||||
return callStartString + "(" + argumentsStr + ")." + mutator->second + "(" +
|
||||
rhs + ")";
|
||||
@@ -318,17 +322,30 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
condition.SetParameters(parameters);
|
||||
}
|
||||
|
||||
gd::EventsCodeGenerator::CheckBehaviorParameters(condition, instrInfos);
|
||||
// Verify that there are no mismatches between object type in parameters.
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType())) {
|
||||
gd::String objectInParameter =
|
||||
condition.GetParameter(pNb).GetPlainString();
|
||||
|
||||
if (!GetObjectsContainersList().HasObjectOrGroupNamed(objectInParameter)) {
|
||||
const auto &expectedObjectType =
|
||||
instrInfos.parameters[pNb].GetExtraInfo();
|
||||
const auto &actualObjectType =
|
||||
GetObjectsContainersList().GetTypeOfObject(objectInParameter);
|
||||
if (!GetObjectsContainersList().HasObjectOrGroupNamed(
|
||||
objectInParameter)) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
|
||||
objectInParameter, "");
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!instrInfos.parameters[pNb].GetExtraInfo().empty() &&
|
||||
GetObjectsContainersList().GetTypeOfObject(objectInParameter) !=
|
||||
instrInfos.parameters[pNb].GetExtraInfo()) {
|
||||
} else if (!expectedObjectType.empty() &&
|
||||
actualObjectType != expectedObjectType) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
|
||||
actualObjectType, expectedObjectType, objectInParameter);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
@@ -364,15 +381,22 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
}
|
||||
}
|
||||
} else if (instrInfos.IsBehaviorInstruction()) {
|
||||
gd::String objectName = condition.GetParameter(0).GetPlainString();
|
||||
gd::String behaviorType = GetObjectsContainersList().GetTypeOfBehavior(condition.GetParameter(1).GetPlainString());
|
||||
if (instrInfos.parameters.size() >= 2) {
|
||||
const gd::String &objectName = condition.GetParameter(0).GetPlainString();
|
||||
const gd::String &behaviorName =
|
||||
condition.GetParameter(1).GetPlainString();
|
||||
const gd::String &actualBehaviorType =
|
||||
GetObjectsContainersList().GetTypeOfBehavior(behaviorName);
|
||||
|
||||
std::vector<gd::String> realObjects =
|
||||
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
|
||||
GetObjectsContainersList().ExpandObjectName(
|
||||
objectName, context.GetCurrentObject());
|
||||
|
||||
const BehaviorMetadata &autoInfo =
|
||||
MetadataProvider::GetBehaviorMetadata(platform, actualBehaviorType);
|
||||
|
||||
for (std::size_t i = 0; i < realObjects.size(); ++i) {
|
||||
// Setup context
|
||||
const BehaviorMetadata& autoInfo =
|
||||
MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
|
||||
AddIncludeFiles(autoInfo.includeFiles);
|
||||
context.SetCurrentObject(realObjects[i]);
|
||||
context.ObjectsListNeeded(realObjects[i]);
|
||||
@@ -382,7 +406,7 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
condition.GetParameters(), instrInfos.parameters, context);
|
||||
conditionCode += GenerateBehaviorCondition(
|
||||
realObjects[i],
|
||||
condition.GetParameter(1).GetPlainString(),
|
||||
behaviorName,
|
||||
autoInfo,
|
||||
arguments,
|
||||
instrInfos,
|
||||
@@ -457,6 +481,33 @@ gd::String EventsCodeGenerator::GenerateConditionsListCode(
|
||||
return outputCode;
|
||||
}
|
||||
|
||||
void EventsCodeGenerator::CheckBehaviorParameters(
|
||||
const gd::Instruction &instruction,
|
||||
const gd::InstructionMetadata &instrInfos) {
|
||||
gd::ParameterMetadataTools::IterateOverParameters(
|
||||
instruction.GetParameters(), instrInfos.parameters,
|
||||
[this](const gd::ParameterMetadata ¶meterMetadata,
|
||||
const gd::Expression ¶meterValue,
|
||||
const gd::String &lastObjectName) {
|
||||
if (ParameterMetadata::IsBehavior(parameterMetadata.GetType())) {
|
||||
const gd::String &behaviorName = parameterValue.GetPlainString();
|
||||
const gd::String &actualBehaviorType =
|
||||
GetObjectsContainersList().GetTypeOfBehaviorInObjectOrGroup(
|
||||
lastObjectName, behaviorName);
|
||||
const gd::String &expectedBehaviorType =
|
||||
parameterMetadata.GetExtraInfo();
|
||||
|
||||
if (!expectedBehaviorType.empty() &&
|
||||
actualBehaviorType != expectedBehaviorType) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MissingBehavior, "",
|
||||
actualBehaviorType, expectedBehaviorType, lastObjectName);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate code for an action.
|
||||
*/
|
||||
@@ -494,15 +545,29 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
action.SetParameters(parameters);
|
||||
}
|
||||
|
||||
gd::EventsCodeGenerator::CheckBehaviorParameters(action, instrInfos);
|
||||
// Verify that there are no mismatches between object type in parameters.
|
||||
for (std::size_t pNb = 0; pNb < instrInfos.parameters.size(); ++pNb) {
|
||||
if (ParameterMetadata::IsObject(instrInfos.parameters[pNb].GetType())) {
|
||||
gd::String objectInParameter = action.GetParameter(pNb).GetPlainString();
|
||||
if (!GetObjectsContainersList().HasObjectOrGroupNamed(objectInParameter)) {
|
||||
|
||||
const auto &expectedObjectType =
|
||||
instrInfos.parameters[pNb].GetExtraInfo();
|
||||
const auto &actualObjectType =
|
||||
GetObjectsContainersList().GetTypeOfObject(objectInParameter);
|
||||
if (!GetObjectsContainersList().HasObjectOrGroupNamed(
|
||||
objectInParameter)) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
|
||||
objectInParameter, "");
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!instrInfos.parameters[pNb].GetExtraInfo().empty() &&
|
||||
GetObjectsContainersList().GetTypeOfObject(objectInParameter) !=
|
||||
instrInfos.parameters[pNb].GetExtraInfo()) {
|
||||
} else if (!expectedObjectType.empty() &&
|
||||
actualObjectType != expectedObjectType) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
|
||||
actualObjectType, expectedObjectType, objectInParameter);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
@@ -540,17 +605,22 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
}
|
||||
}
|
||||
} else if (instrInfos.IsBehaviorInstruction()) {
|
||||
gd::String objectName = action.GetParameter(0).GetPlainString();
|
||||
gd::String behaviorType = GetObjectsContainersList().GetTypeOfBehavior(action.GetParameter(1).GetPlainString());
|
||||
|
||||
if (instrInfos.parameters.size() >= 2) {
|
||||
const gd::String &objectName = action.GetParameter(0).GetPlainString();
|
||||
const gd::String &behaviorName = action.GetParameter(1).GetPlainString();
|
||||
const gd::String &actualBehaviorType =
|
||||
GetObjectsContainersList().GetTypeOfBehavior(behaviorName);
|
||||
|
||||
std::vector<gd::String> realObjects =
|
||||
GetObjectsContainersList().ExpandObjectName(objectName, context.GetCurrentObject());
|
||||
GetObjectsContainersList().ExpandObjectName(
|
||||
objectName, context.GetCurrentObject());
|
||||
|
||||
const BehaviorMetadata &autoInfo =
|
||||
MetadataProvider::GetBehaviorMetadata(platform, actualBehaviorType);
|
||||
|
||||
AddIncludeFiles(autoInfo.includeFiles);
|
||||
for (std::size_t i = 0; i < realObjects.size(); ++i) {
|
||||
// Setup context
|
||||
const BehaviorMetadata& autoInfo =
|
||||
MetadataProvider::GetBehaviorMetadata(platform, behaviorType);
|
||||
AddIncludeFiles(autoInfo.includeFiles);
|
||||
context.SetCurrentObject(realObjects[i]);
|
||||
context.ObjectsListNeeded(realObjects[i]);
|
||||
|
||||
@@ -559,7 +629,7 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
action.GetParameters(), instrInfos.parameters, context);
|
||||
actionCode +=
|
||||
GenerateBehaviorAction(realObjects[i],
|
||||
action.GetParameter(1).GetPlainString(),
|
||||
behaviorName,
|
||||
autoInfo,
|
||||
functionCallName,
|
||||
arguments,
|
||||
@@ -583,6 +653,29 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
return actionCode;
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateLocalVariablesStackAccessor() {
|
||||
return (HasProjectAndLayout() ? GetCodeNamespace()
|
||||
: "eventsFunctionContext") +
|
||||
".localVariables";
|
||||
}
|
||||
|
||||
gd::String EventsCodeGenerator::GenerateAnyOrSceneVariableGetter(
|
||||
const gd::Expression &variableExpression,
|
||||
EventsCodeGenerationContext &context) {
|
||||
const auto variableName = gd::ExpressionVariableNameFinder::GetVariableName(
|
||||
*variableExpression.GetRootNode());
|
||||
|
||||
gd::String variableParameterType =
|
||||
GetProjectScopedContainers().GetVariablesContainersList().Has(
|
||||
variableName)
|
||||
? "variable"
|
||||
: "scenevar";
|
||||
|
||||
return gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, variableParameterType,
|
||||
variableExpression.GetPlainString(), "", "AllowUndeclaredVariable");
|
||||
}
|
||||
|
||||
const EventsCodeGenerator::CallbackDescriptor
|
||||
EventsCodeGenerator::GenerateCallback(
|
||||
const gd::String& callbackID,
|
||||
@@ -607,14 +700,23 @@ EventsCodeGenerator::GenerateCallback(
|
||||
actionsCode += "} //End of subevents\n";
|
||||
}
|
||||
|
||||
gd::String restoreLocalVariablesCode;
|
||||
restoreLocalVariablesCode +=
|
||||
"asyncObjectsList.restoreLocalVariablesContainers(" +
|
||||
GenerateLocalVariablesStackAccessor() + ");\n";
|
||||
|
||||
// Compose the callback function and add outside main
|
||||
const gd::String actionsDeclarationsCode =
|
||||
GenerateObjectsDeclarationCode(callbackContext);
|
||||
|
||||
const gd::String clearLocalVariablesCode =
|
||||
GenerateLocalVariablesStackAccessor() + ".length = 0;\n";
|
||||
|
||||
const gd::String callbackCode = callbackFunctionName + " = function (" +
|
||||
GenerateEventsParameters(callbackContext) +
|
||||
") {\n" + actionsDeclarationsCode +
|
||||
actionsCode + "}\n";
|
||||
") {\n" + restoreLocalVariablesCode +
|
||||
actionsDeclarationsCode + actionsCode +
|
||||
clearLocalVariablesCode + "}\n";
|
||||
|
||||
AddCustomCodeOutsideMain(callbackCode);
|
||||
|
||||
@@ -677,13 +779,13 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
|
||||
if (ParameterMetadata::IsExpression("number", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, "number", parameter, lastObjectName);
|
||||
*this, context, "number", parameter, lastObjectName, metadata.GetExtraInfo());
|
||||
} else if (ParameterMetadata::IsExpression("string", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, "string", parameter, lastObjectName);
|
||||
*this, context, "string", parameter, lastObjectName, metadata.GetExtraInfo());
|
||||
} else if (ParameterMetadata::IsExpression("variable", metadata.GetType())) {
|
||||
argOutput = gd::ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
*this, context, metadata.GetType(), parameter, lastObjectName);
|
||||
*this, context, metadata.GetType(), parameter, lastObjectName, metadata.GetExtraInfo());
|
||||
} 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.
|
||||
@@ -695,7 +797,8 @@ gd::String EventsCodeGenerator::GenerateParameterCodes(
|
||||
} else if (metadata.GetType() == "operator") {
|
||||
argOutput += parameter.GetPlainString();
|
||||
if (argOutput != "=" && argOutput != "+" && argOutput != "-" &&
|
||||
argOutput != "/" && argOutput != "*") {
|
||||
argOutput != "/" && argOutput != "*" && argOutput != "True" &&
|
||||
argOutput != "False" && argOutput != "Toggle") {
|
||||
cout << "Warning: Bad operator: Set to = by default." << endl;
|
||||
argOutput = "=";
|
||||
}
|
||||
@@ -865,6 +968,11 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
|
||||
gd::EventsList& events, EventsCodeGenerationContext& parentContext) {
|
||||
gd::String output;
|
||||
for (std::size_t eId = 0; eId < events.size(); ++eId) {
|
||||
auto& event = events[eId];
|
||||
if (event.HasVariables()) {
|
||||
GetProjectScopedContainers().GetVariablesContainersList().Push(event.GetVariables());
|
||||
}
|
||||
|
||||
// Each event has its own context : Objects picked in an event are totally
|
||||
// different than the one picked in another.
|
||||
gd::EventsCodeGenerationContext newContext;
|
||||
@@ -885,13 +993,17 @@ gd::String EventsCodeGenerator::GenerateEventsListCode(
|
||||
|
||||
auto& context = reuseParentContext ? reusedContext : newContext;
|
||||
|
||||
gd::String eventCoreCode = events[eId].GenerateEventCode(*this, context);
|
||||
gd::String eventCoreCode = event.GenerateEventCode(*this, context);
|
||||
gd::String scopeBegin = GenerateScopeBegin(context);
|
||||
gd::String scopeEnd = GenerateScopeEnd(context);
|
||||
gd::String declarationsCode = GenerateObjectsDeclarationCode(context);
|
||||
|
||||
output += "\n" + scopeBegin + "\n" + declarationsCode + "\n" +
|
||||
eventCoreCode + "\n" + scopeEnd + "\n";
|
||||
|
||||
if (event.HasVariables()) {
|
||||
GetProjectScopedContainers().GetVariablesContainersList().Pop();
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
@@ -1067,7 +1179,8 @@ gd::String EventsCodeGenerator::GenerateFreeAction(
|
||||
// Generate call
|
||||
gd::String call;
|
||||
if (instrInfos.codeExtraInformation.type == "number" ||
|
||||
instrInfos.codeExtraInformation.type == "string") {
|
||||
instrInfos.codeExtraInformation.type == "string" ||
|
||||
instrInfos.codeExtraInformation.type == "boolean") {
|
||||
if (instrInfos.codeExtraInformation.accessType ==
|
||||
gd::InstructionMetadata::ExtraInformation::MutatorAndOrAccessor)
|
||||
call = GenerateOperatorCall(
|
||||
@@ -1251,7 +1364,8 @@ EventsCodeGenerator::EventsCodeGenerator(const gd::Project& project_,
|
||||
compilationForRuntime(false),
|
||||
maxCustomConditionsDepth(0),
|
||||
maxConditionsListsSize(0),
|
||||
eventsListNextUniqueId(0){};
|
||||
eventsListNextUniqueId(0),
|
||||
diagnosticReport(nullptr){};
|
||||
|
||||
EventsCodeGenerator::EventsCodeGenerator(
|
||||
const gd::Platform& platform_,
|
||||
@@ -1265,6 +1379,7 @@ EventsCodeGenerator::EventsCodeGenerator(
|
||||
compilationForRuntime(false),
|
||||
maxCustomConditionsDepth(0),
|
||||
maxConditionsListsSize(0),
|
||||
eventsListNextUniqueId(0){};
|
||||
eventsListNextUniqueId(0),
|
||||
diagnosticReport(nullptr){};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EVENTSCODEGENERATOR_H
|
||||
#define GDCORE_EVENTSCODEGENERATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <set>
|
||||
#include <utility>
|
||||
@@ -12,8 +11,10 @@
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Events/CodeGeneration/DiagnosticReport.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class EventsList;
|
||||
class Expression;
|
||||
@@ -336,6 +337,16 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Give access to the project scoped containers as code generation might
|
||||
* push and pop variable containers (for local variables).
|
||||
* This could be passed as a parameter recursively in code generation, but this requires
|
||||
* heavy refactoring. Instead, we use this single instance.
|
||||
*/
|
||||
gd::ProjectScopedContainers& GetProjectScopedContainers() {
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the code generation is done for a given project and
|
||||
* layout. If not, this means that the code is generated for a function.
|
||||
@@ -372,6 +383,14 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
*/
|
||||
size_t GetMaxConditionsListsSize() const { return maxConditionsListsSize; }
|
||||
|
||||
void SetDiagnosticReport(gd::DiagnosticReport* diagnosticReport_) {
|
||||
diagnosticReport = diagnosticReport_;
|
||||
}
|
||||
|
||||
gd::DiagnosticReport* GetDiagnosticReport() {
|
||||
return diagnosticReport;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Generate the full name for accessing to a boolean variable used for
|
||||
* conditions.
|
||||
@@ -448,7 +467,7 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
*/
|
||||
virtual gd::String GetCodeNamespace() { return ""; };
|
||||
|
||||
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE };
|
||||
enum VariableScope { LAYOUT_VARIABLE = 0, PROJECT_VARIABLE, OBJECT_VARIABLE, ANY_VARIABLE };
|
||||
|
||||
/**
|
||||
* Generate a single unique number for the specified instruction.
|
||||
@@ -478,7 +497,20 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
const gd::String& lhs,
|
||||
const gd::String& rhs);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Generate the code to access the local variables stack.
|
||||
*/
|
||||
virtual gd::String GenerateLocalVariablesStackAccessor();
|
||||
|
||||
/**
|
||||
* \brief Generate an any variable getter that fallbacks on scene variable for
|
||||
* compatibility reason.
|
||||
*/
|
||||
gd::String
|
||||
GenerateAnyOrSceneVariableGetter(const gd::Expression &variableExpression,
|
||||
EventsCodeGenerationContext &context);
|
||||
|
||||
protected:
|
||||
virtual const gd::String GenerateRelationalOperatorCodes(
|
||||
const gd::String& operatorString);
|
||||
|
||||
@@ -534,11 +566,15 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
const VariableScope& scope,
|
||||
gd::EventsCodeGenerationContext& context,
|
||||
const gd::String& objectName) {
|
||||
// This code is only used as a mock.
|
||||
// See the real implementation in GDJS.
|
||||
if (scope == LAYOUT_VARIABLE) {
|
||||
return "getLayoutVariable(" + variableName + ")";
|
||||
|
||||
} else if (scope == PROJECT_VARIABLE) {
|
||||
return "getProjectVariable(" + variableName + ")";
|
||||
} else if (scope == ANY_VARIABLE) {
|
||||
return "getAnyVariable(" + variableName + ")";
|
||||
}
|
||||
|
||||
return "getVariableForObject(" + objectName + ", " + variableName + ")";
|
||||
@@ -779,6 +815,10 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
virtual gd::String GenerateGetBehaviorNameCode(
|
||||
const gd::String& behaviorName);
|
||||
|
||||
void CheckBehaviorParameters(
|
||||
const gd::Instruction &instruction,
|
||||
const gd::InstructionMetadata &instrInfos);
|
||||
|
||||
const gd::Platform& platform; ///< The platform being used.
|
||||
|
||||
gd::ProjectScopedContainers projectScopedContainers;
|
||||
@@ -809,8 +849,9 @@ class GD_CORE_API EventsCodeGenerator {
|
||||
instructionUniqueIds; ///< The unique ids generated for instructions.
|
||||
size_t eventsListNextUniqueId; ///< The next identifier to use for an events
|
||||
///< list function name.
|
||||
|
||||
gd::DiagnosticReport* diagnosticReport;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EVENTSCODEGENERATOR_H
|
||||
|
@@ -31,6 +31,7 @@
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
#include "GDCore/Events/CodeGeneration/DiagnosticReport.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -39,7 +40,8 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& rootType,
|
||||
const gd::Expression& expression,
|
||||
const gd::String& rootObjectName) {
|
||||
const gd::String& rootObjectName,
|
||||
const gd::String& extraInfo) {
|
||||
ExpressionCodeGenerator generator(rootType, rootObjectName, codeGenerator, context);
|
||||
|
||||
auto node = expression.GetRootNode();
|
||||
@@ -52,13 +54,34 @@ gd::String ExpressionCodeGenerator::GenerateExpressionCode(
|
||||
|
||||
gd::ExpressionValidator validator(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetProjectScopedContainers(),
|
||||
rootType);
|
||||
rootType,
|
||||
extraInfo);
|
||||
node->Visit(validator);
|
||||
if (!validator.GetFatalErrors().empty()) {
|
||||
std::cout << "Error: \"" << validator.GetFatalErrors()[0]->GetMessage()
|
||||
<< "\" in: \"" << expression.GetPlainString() << "\" ("
|
||||
<< rootType << ")" << std::endl;
|
||||
|
||||
auto *diagnosticReport = codeGenerator.GetDiagnosticReport();
|
||||
if (diagnosticReport) {
|
||||
for (auto *error : validator.GetFatalErrors()) {
|
||||
if (error->GetType() ==
|
||||
gd::ExpressionParserError::ErrorType::UndeclaredVariable ||
|
||||
error->GetType() ==
|
||||
gd::ExpressionParserError::ErrorType::UnknownIdentifier) {
|
||||
|
||||
const auto& variableName = error->GetActualValue();
|
||||
if (!variableName.empty()) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::UndeclaredVariable,
|
||||
error->GetMessage(), error->GetActualValue(),
|
||||
"", error->GetObjectName());
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return generator.GenerateDefaultValue(rootType);
|
||||
}
|
||||
|
||||
@@ -110,11 +133,13 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
|
||||
if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
// The node is a variable inside an expression waiting for a *variable* to be returned, not its value.
|
||||
EventsCodeGenerator::VariableScope scope =
|
||||
type == "globalvar"
|
||||
type == "variable"
|
||||
? gd::EventsCodeGenerator::ANY_VARIABLE
|
||||
: type == "globalvar"
|
||||
? gd::EventsCodeGenerator::PROJECT_VARIABLE
|
||||
: ((type == "scenevar")
|
||||
: type == "scenevar"
|
||||
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
|
||||
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetObjectsContainersList(),
|
||||
@@ -137,19 +162,8 @@ void ExpressionCodeGenerator::OnVisitVariableNode(VariableNode& node) {
|
||||
|
||||
output += codeGenerator.GenerateVariableValueAs(type);
|
||||
}, [&]() {
|
||||
if (!codeGenerator.HasProjectAndLayout()) {
|
||||
gd::LogWarning("Tried to generate access to a variable without a project/scene - the code generator only works for global and scene variables for now.");
|
||||
output += GenerateDefaultValue(type);
|
||||
return;
|
||||
}
|
||||
|
||||
// This could be adapted in the future if more scopes are supported.
|
||||
EventsCodeGenerator::VariableScope scope = gd::EventsCodeGenerator::PROJECT_VARIABLE;
|
||||
if (codeGenerator.GetProjectScopedContainers().GetVariablesContainersList().GetBottomMostVariablesContainer()->Has(node.name)) {
|
||||
scope = gd::EventsCodeGenerator::LAYOUT_VARIABLE;
|
||||
}
|
||||
|
||||
output += codeGenerator.GenerateGetVariable(node.name, scope, context, "");
|
||||
output += codeGenerator.GenerateGetVariable(
|
||||
node.name, gd::EventsCodeGenerator::ANY_VARIABLE, context, "");
|
||||
if (node.child) node.child->Visit(*this);
|
||||
output += codeGenerator.GenerateVariableValueAs(type);
|
||||
}, [&]() {
|
||||
@@ -209,11 +223,13 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
|
||||
codeGenerator.GenerateObject(node.identifierName, type, context);
|
||||
} else if (gd::ParameterMetadata::IsExpression("variable", type)) {
|
||||
EventsCodeGenerator::VariableScope scope =
|
||||
type == "globalvar"
|
||||
type == "variable"
|
||||
? gd::EventsCodeGenerator::ANY_VARIABLE
|
||||
: type == "globalvar"
|
||||
? gd::EventsCodeGenerator::PROJECT_VARIABLE
|
||||
: ((type == "scenevar")
|
||||
: type == "scenevar"
|
||||
? gd::EventsCodeGenerator::LAYOUT_VARIABLE
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE);
|
||||
: gd::EventsCodeGenerator::OBJECT_VARIABLE;
|
||||
|
||||
auto objectName = gd::ExpressionVariableOwnerFinder::GetObjectName(codeGenerator.GetPlatform(),
|
||||
codeGenerator.GetObjectsContainersList(),
|
||||
@@ -236,19 +252,9 @@ void ExpressionCodeGenerator::OnVisitIdentifierNode(IdentifierNode& node) {
|
||||
node.childIdentifierName, gd::EventsCodeGenerator::OBJECT_VARIABLE, context, node.identifierName);
|
||||
output += codeGenerator.GenerateVariableValueAs(type);
|
||||
}, [&]() {
|
||||
if (!codeGenerator.HasProjectAndLayout()) {
|
||||
gd::LogWarning("Tried to generate access to a variable without a project/scene - the code generator only works for global and scene variables for now.");
|
||||
output += GenerateDefaultValue(type);
|
||||
return;
|
||||
}
|
||||
|
||||
// This could be adapted in the future if more scopes are supported at runtime.
|
||||
EventsCodeGenerator::VariableScope scope = gd::EventsCodeGenerator::PROJECT_VARIABLE;
|
||||
if (variablesContainersList.GetBottomMostVariablesContainer()->Has(node.identifierName)) {
|
||||
scope = gd::EventsCodeGenerator::LAYOUT_VARIABLE;
|
||||
}
|
||||
|
||||
output += codeGenerator.GenerateGetVariable(node.identifierName, scope, context, "");
|
||||
output += codeGenerator.GenerateGetVariable(
|
||||
node.identifierName, gd::EventsCodeGenerator::ANY_VARIABLE, context,
|
||||
"");
|
||||
if (!node.childIdentifierName.empty()) {
|
||||
output += codeGenerator.GenerateVariableAccessor(node.childIdentifierName);
|
||||
}
|
||||
|
@@ -59,7 +59,8 @@ class GD_CORE_API ExpressionCodeGenerator : public ExpressionParser2NodeWorker {
|
||||
EventsCodeGenerationContext& context,
|
||||
const gd::String& type,
|
||||
const gd::Expression& expression,
|
||||
const gd::String& objectName = "");
|
||||
const gd::String& objectName = "",
|
||||
const gd::String& extraInfo = "");
|
||||
|
||||
const gd::String& GetOutput() { return output; };
|
||||
|
||||
|
@@ -17,6 +17,7 @@
|
||||
namespace gd {
|
||||
|
||||
EventsList BaseEvent::badSubEvents;
|
||||
VariablesContainer BaseEvent::badLocalVariables;
|
||||
std::vector<gd::String> BaseEvent::emptyDependencies;
|
||||
gd::String BaseEvent::emptySourceFile;
|
||||
|
||||
@@ -28,6 +29,8 @@ BaseEvent::BaseEvent()
|
||||
|
||||
bool BaseEvent::HasSubEvents() const { return !GetSubEvents().IsEmpty(); }
|
||||
|
||||
bool BaseEvent::HasVariables() const { return GetVariables().Count() > 0; }
|
||||
|
||||
gd::String BaseEvent::GenerateEventCode(
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context) {
|
||||
|
@@ -3,9 +3,7 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef GDCORE_EVENT_H
|
||||
#define GDCORE_EVENT_H
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@@ -26,6 +24,7 @@ class SerializerElement;
|
||||
class Instruction;
|
||||
class EventVisitor;
|
||||
class ReadOnlyEventVisitor;
|
||||
class VariablesContainer;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -92,6 +91,32 @@ class GD_CORE_API BaseEvent {
|
||||
*/
|
||||
bool HasSubEvents() const;
|
||||
|
||||
/**
|
||||
* Derived class have to redefine this function, so as to return true, if they
|
||||
* can have local variables.
|
||||
*/
|
||||
virtual bool CanHaveVariables() const { return false; }
|
||||
|
||||
/**
|
||||
* Return the local variables, if applicable.
|
||||
*/
|
||||
virtual const gd::VariablesContainer& GetVariables() const {
|
||||
return badLocalVariables;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the local variables, if applicable.
|
||||
*/
|
||||
virtual gd::VariablesContainer& GetVariables() {
|
||||
return badLocalVariables;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Return true if the events has local variables.
|
||||
* \warning This is only applicable when CanHaveVariables() return true.
|
||||
*/
|
||||
bool HasVariables() const;
|
||||
|
||||
/**
|
||||
* \brief Return a list of all conditions of the event.
|
||||
* \note Used to preprocess or search in the conditions.
|
||||
@@ -301,6 +326,7 @@ class GD_CORE_API BaseEvent {
|
||||
///< Used for saving the event for instance.
|
||||
|
||||
static gd::EventsList badSubEvents;
|
||||
static gd::VariablesContainer badLocalVariables;
|
||||
static std::vector<gd::String> emptyDependencies;
|
||||
static gd::String emptySourceFile;
|
||||
};
|
||||
@@ -325,6 +351,3 @@ class EmptyEvent : public BaseEvent {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EVENT_H
|
||||
#endif
|
||||
|
@@ -18,7 +18,6 @@ class BaseEvent;
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
class TiXmlElement;
|
||||
|
||||
#undef CreateEvent
|
||||
|
||||
|
@@ -38,7 +38,7 @@ using namespace gd::GrammarTerminals;
|
||||
* parser by refactoring out the dependency on gd::MetadataProvider (injecting
|
||||
* instead functions to be called to query supported functions).
|
||||
*
|
||||
* \see gd::ExpressionParserDiagnostic
|
||||
* \see gd::ExpressionParserError
|
||||
* \see gd::ExpressionNode
|
||||
*/
|
||||
class GD_CORE_API ExpressionParser2 {
|
||||
@@ -547,28 +547,28 @@ class GD_CORE_API ExpressionParser2 {
|
||||
}
|
||||
///@}
|
||||
|
||||
std::unique_ptr<ExpressionParserDiagnostic> ValidateOperator(
|
||||
std::unique_ptr<ExpressionParserError> ValidateOperator(
|
||||
gd::String::value_type operatorChar) {
|
||||
if (operatorChar == '+' || operatorChar == '-' || operatorChar == '/' ||
|
||||
operatorChar == '*') {
|
||||
return gd::make_unique<ExpressionParserDiagnostic>();
|
||||
return std::unique_ptr<ExpressionParserError>(nullptr);
|
||||
}
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
gd::ExpressionParserError::ErrorType::InvalidOperator,
|
||||
_("You've used an operator that is not supported. Operator should be "
|
||||
"either +, -, / or *."),
|
||||
GetCurrentPosition());
|
||||
}
|
||||
|
||||
std::unique_ptr<ExpressionParserDiagnostic> ValidateUnaryOperator(
|
||||
std::unique_ptr<ExpressionParserError> ValidateUnaryOperator(
|
||||
gd::String::value_type operatorChar,
|
||||
size_t position) {
|
||||
if (operatorChar == '+' || operatorChar == '-') {
|
||||
return gd::make_unique<ExpressionParserDiagnostic>();
|
||||
return std::unique_ptr<ExpressionParserError>(nullptr);
|
||||
}
|
||||
|
||||
return gd::make_unique<ExpressionParserError>(
|
||||
"invalid_operator",
|
||||
gd::ExpressionParserError::ErrorType::InvalidOperator,
|
||||
_("You've used an \"unary\" operator that is not supported. Operator "
|
||||
"should be "
|
||||
"either + or -."),
|
||||
@@ -719,13 +719,15 @@ class GD_CORE_API ExpressionParser2 {
|
||||
std::unique_ptr<ExpressionParserError> RaiseSyntaxError(
|
||||
const gd::String &message) {
|
||||
return std::move(gd::make_unique<ExpressionParserError>(
|
||||
"syntax_error", message, GetCurrentPosition()));
|
||||
gd::ExpressionParserError::ErrorType::SyntaxError, message,
|
||||
GetCurrentPosition()));
|
||||
}
|
||||
|
||||
std::unique_ptr<ExpressionParserError> RaiseTypeError(
|
||||
const gd::String &message, size_t beginningPosition) {
|
||||
return std::move(gd::make_unique<ExpressionParserError>(
|
||||
"type_error", message, beginningPosition, GetCurrentPosition()));
|
||||
gd::ExpressionParserError::ErrorType::MismatchedType, message,
|
||||
beginningPosition, GetCurrentPosition()));
|
||||
}
|
||||
///@}
|
||||
|
||||
|
@@ -6,5 +6,5 @@
|
||||
#include "ExpressionParser2Node.h"
|
||||
|
||||
namespace gd {
|
||||
gd::String ExpressionParserDiagnostic::noMessage = "";
|
||||
|
||||
}
|
@@ -3,14 +3,14 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONPARSER2NODES_H
|
||||
#define GDCORE_EXPRESSIONPARSER2NODES_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ObjectsContainer;
|
||||
@@ -40,50 +40,57 @@ struct GD_CORE_API ExpressionParserLocation {
|
||||
size_t endPosition;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief A diagnostic that can be attached to a gd::ExpressionNode.
|
||||
*/
|
||||
struct GD_CORE_API ExpressionParserDiagnostic {
|
||||
virtual ~ExpressionParserDiagnostic() = default;
|
||||
virtual bool IsError() { return false; }
|
||||
virtual const gd::String &GetMessage() { return noMessage; }
|
||||
virtual size_t GetStartPosition() { return 0; }
|
||||
virtual size_t GetEndPosition() { return 0; }
|
||||
|
||||
private:
|
||||
static gd::String noMessage;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An error that can be attached to a gd::ExpressionNode.
|
||||
*/
|
||||
struct GD_CORE_API ExpressionParserError : public ExpressionParserDiagnostic {
|
||||
ExpressionParserError(const gd::String &type_,
|
||||
struct GD_CORE_API ExpressionParserError {
|
||||
enum ErrorType {
|
||||
SyntaxError,
|
||||
InvalidOperator,
|
||||
MismatchedType,
|
||||
UndeclaredVariable,
|
||||
UnknownIdentifier,
|
||||
BracketsNotAllowedForObjects,
|
||||
TooFewParameters,
|
||||
TooManyParameters,
|
||||
InvalidFunctionName,
|
||||
MalformedVariableParameter,
|
||||
MalformedObjectParameter,
|
||||
UnknownParameterType,
|
||||
MissingBehavior,
|
||||
VariableNameCollision,
|
||||
};
|
||||
|
||||
ExpressionParserError(gd::ExpressionParserError::ErrorType type_,
|
||||
const gd::String &message_,
|
||||
const ExpressionParserLocation &location_)
|
||||
: type(type_), message(message_), location(location_){};
|
||||
ExpressionParserError(const gd::String &type_,
|
||||
const gd::String &message_,
|
||||
size_t position_)
|
||||
const ExpressionParserLocation &location_,
|
||||
const gd::String &actualValue_ = "",
|
||||
const gd::String &objectName_ = "")
|
||||
: type(type_), message(message_), location(location_),
|
||||
actualValue(actualValue_), objectName(objectName_){};
|
||||
ExpressionParserError(gd::ExpressionParserError::ErrorType type_,
|
||||
const gd::String &message_, size_t position_)
|
||||
: type(type_), message(message_), location(position_){};
|
||||
ExpressionParserError(const gd::String &type_,
|
||||
const gd::String &message_,
|
||||
size_t startPosition_,
|
||||
ExpressionParserError(gd::ExpressionParserError::ErrorType type_,
|
||||
const gd::String &message_, size_t startPosition_,
|
||||
size_t endPosition_)
|
||||
: type(type_),
|
||||
message(message_),
|
||||
: type(type_), message(message_),
|
||||
location(startPosition_, endPosition_){};
|
||||
virtual ~ExpressionParserError(){};
|
||||
|
||||
bool IsError() override { return true; }
|
||||
const gd::String &GetMessage() override { return message; }
|
||||
size_t GetStartPosition() override { return location.GetStartPosition(); }
|
||||
size_t GetEndPosition() override { return location.GetEndPosition(); }
|
||||
gd::ExpressionParserError::ErrorType GetType() { return type; }
|
||||
const gd::String &GetMessage() { return message; }
|
||||
const gd::String &GetObjectName() { return objectName; }
|
||||
const gd::String &GetActualValue() { return actualValue; }
|
||||
size_t GetStartPosition() { return location.GetStartPosition(); }
|
||||
size_t GetEndPosition() { return location.GetEndPosition(); }
|
||||
|
||||
private:
|
||||
gd::String type;
|
||||
private:
|
||||
gd::ExpressionParserError::ErrorType type;
|
||||
gd::String message;
|
||||
ExpressionParserLocation location;
|
||||
gd::String objectName;
|
||||
gd::String actualValue;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -95,7 +102,7 @@ struct GD_CORE_API ExpressionNode {
|
||||
virtual ~ExpressionNode(){};
|
||||
virtual void Visit(ExpressionParser2NodeWorker &worker){};
|
||||
|
||||
std::unique_ptr<ExpressionParserDiagnostic> diagnostic;
|
||||
std::unique_ptr<ExpressionParserError> diagnostic;
|
||||
ExpressionParserLocation location; ///< The location of the entire node. Some
|
||||
/// nodes might have other locations
|
||||
/// stored inside them. For example, a
|
||||
@@ -425,5 +432,3 @@ struct GD_CORE_API EmptyNode : public FunctionCallOrObjectFunctionNameOrEmptyNod
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
||||
|
@@ -66,6 +66,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
// Deprecated
|
||||
extension
|
||||
.AddAction("CopyArgumentToVariable",
|
||||
_("Copy function parameter to variable"),
|
||||
@@ -78,9 +79,25 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
.SetHelpPath("/events/functions/return")
|
||||
.AddParameter("functionParameterName", _("Parameter name"), "variable")
|
||||
.AddParameter("scenevar", _("Scene variable"))
|
||||
.SetHidden()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("CopyArgumentToVariable2",
|
||||
_("Copy function parameter to variable"),
|
||||
_("Copy a function parameter (also called \"argument\") to a variable. "
|
||||
"The parameter type must be a variable."),
|
||||
_("Copy the parameter _PARAM0_ into the variable _PARAM1_"),
|
||||
"",
|
||||
"res/function32.png",
|
||||
"res/function32.png")
|
||||
.SetHelpPath("/events/functions/return")
|
||||
.AddParameter("functionParameterName", _("Parameter name"), "variable")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
// Deprecated
|
||||
extension
|
||||
.AddAction("CopyVariableToArgument",
|
||||
_("Copy variable to function parameter"),
|
||||
@@ -93,6 +110,21 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsAdvancedExtension(
|
||||
.SetHelpPath("/events/functions/return")
|
||||
.AddParameter("functionParameterName", _("Parameter name"), "variable")
|
||||
.AddParameter("scenevar", _("Scene variable"))
|
||||
.SetHidden()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("CopyVariableToArgument2",
|
||||
_("Copy variable to function parameter"),
|
||||
_("Copy a variable to function parameter (also called \"argument\"). "
|
||||
"The parameter type must be a variable."),
|
||||
_("Copy the variable _PARAM1_ into the parameter _PARAM0_"),
|
||||
"",
|
||||
"res/function32.png",
|
||||
"res/function32.png")
|
||||
.SetHelpPath("/events/functions/return")
|
||||
.AddParameter("functionParameterName", _("Parameter name"), "variable")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
|
@@ -417,6 +417,93 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.SetDefaultValue("\"\"")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
obj.AddAction("SetNumberObjectVariable",
|
||||
_("Change variable value"),
|
||||
_("Modify the number value of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("SetStringObjectVariable",
|
||||
_("Change text variable"),
|
||||
_("Modify the text of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("SetBooleanObjectVariable",
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of an object variable."),
|
||||
_("Change the variable _PARAM1_ of _PARAM0_: _PARAM2_"),
|
||||
_("Variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("operator", _("Value"), "boolean")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("yesorno", _("Value"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddCondition("NumberObjectVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the number value of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddCondition("StringObjectVariable",
|
||||
_("Text variable"),
|
||||
_("Compare the text of an object variable."),
|
||||
_("the variable _PARAM1_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddCondition("BooleanObjectVariable",
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of an object variable."),
|
||||
_("The variable _PARAM1_ of _PARAM0_ is _PARAM2_"),
|
||||
_("Variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("yesorno", _("Value"))
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("ModVarObjet",
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of an object variable."),
|
||||
@@ -428,7 +515,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction("ModVarObjetTxt",
|
||||
_("Change text variable"),
|
||||
@@ -441,7 +529,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction("SetObjectVariableAsBoolean",
|
||||
_("Change boolean variable"),
|
||||
@@ -454,7 +543,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("New Value:"));
|
||||
.AddParameter("trueorfalse", _("New Value:"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"ToggleObjectVariableAsBoolean",
|
||||
@@ -469,7 +559,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
"res/actions/var.png")
|
||||
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"));
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("ObjectVariableChildExists",
|
||||
_("Child existence"),
|
||||
@@ -657,7 +748,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions());
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("VarObjetTxt",
|
||||
_("Text variable"),
|
||||
@@ -670,7 +762,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions());
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("ObjectVariableAsBoolean",
|
||||
_("Boolean variable"),
|
||||
@@ -683,7 +776,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true");
|
||||
.SetDefaultValue("true")
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddCondition("VarObjetDef",
|
||||
"Variable defined",
|
||||
@@ -697,6 +791,48 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("string", _("Variable"))
|
||||
.SetHidden(); // Deprecated.
|
||||
|
||||
obj.AddAction(
|
||||
"PushStringToObjectVariable",
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) to the end of an object array variable."),
|
||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction("PushNumberToObjectVariable",
|
||||
_("Add variable array value"),
|
||||
_("Adds a number to the end of an object array variable."),
|
||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"PushBooleanToObjectVariable",
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean to the end of an object array variable."),
|
||||
_("Add value _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForLayoutEventsOnly();
|
||||
|
||||
// Deprecated
|
||||
obj.AddAction(
|
||||
"ObjectVariablePush",
|
||||
_("Add existing variable"),
|
||||
@@ -708,6 +844,23 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("scenevar", _("Scene variable with the content to add"))
|
||||
.SetParameterLongDescription(_("The content of the object variable will "
|
||||
"*be copied* and added at the "
|
||||
"end of the array."))
|
||||
.MarkAsAdvanced()
|
||||
.SetHidden();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariablePush2",
|
||||
_("Add existing variable"),
|
||||
_("Adds an existing variable to the end of an object array variable."),
|
||||
_("Add variable _PARAM2_ to array variable _PARAM1_ of _PARAM0_"),
|
||||
_("Variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("variable", _("Scene variable with the content to add"))
|
||||
.SetParameterLongDescription(_("The content of the object variable will "
|
||||
"*be copied* and added at the "
|
||||
"end of the array."))
|
||||
@@ -724,7 +877,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction("ObjectVariablePushNumber",
|
||||
_("Add number variable"),
|
||||
@@ -736,7 +890,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariablePushBool",
|
||||
@@ -749,7 +904,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddAction(
|
||||
"ObjectVariableRemoveAt",
|
||||
@@ -1203,7 +1359,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"));
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddExpression(
|
||||
"VariableChildCount",
|
||||
@@ -1220,7 +1377,8 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
_("Variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("object", _("Object"))
|
||||
.AddParameter("objectvar", _("Variable"));
|
||||
.AddParameter("objectvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
obj.AddExpression("ObjectTimerElapsedTime",
|
||||
_("Object timer value"),
|
||||
|
@@ -327,6 +327,25 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsCameraExtension(
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"CameraZoom",
|
||||
_("Camera zoom"),
|
||||
_("Compare the zoom of a camera of a layer."),
|
||||
_("Zoom of camera _PARAM2_ of layer _PARAM1_"),
|
||||
"",
|
||||
"res/conditions/camera24.png",
|
||||
"res/conditions/camera.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("layer", _("Layer"), "", true)
|
||||
.SetDefaultValue("\"\"")
|
||||
.AddParameter("expression", _("Camera number (default : 0)"), "", true)
|
||||
.SetDefaultValue("0")
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", gd::ParameterOptions::MakeNewOptions().SetDescription(
|
||||
_("Zoom")))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"FixCamera",
|
||||
|
@@ -68,19 +68,22 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
|
||||
extension
|
||||
.AddStrExpression("ToJSON",
|
||||
_("Convert scene variable to JSON"),
|
||||
_("Convert a scene variable to JSON"),
|
||||
_("Convert variable to JSON"),
|
||||
_("Convert a variable to JSON"),
|
||||
_("JSON"),
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("scenevar", _("Scene variable to be stringified"));
|
||||
.AddParameter("variable", _("The variable to be stringified"),
|
||||
"AllowUndeclaredVariable");
|
||||
|
||||
// Deprecated
|
||||
extension
|
||||
.AddStrExpression("GlobalVarToJSON",
|
||||
_("Convert global variable to JSON"),
|
||||
_("Convert a global variable to JSON"),
|
||||
_("JSON"),
|
||||
"res/conditions/toujours24_black.png")
|
||||
.AddParameter("globalvar", _("The global variable to be stringified"));
|
||||
.AddParameter("globalvar", _("The global variable to be stringified"))
|
||||
.SetHidden();
|
||||
|
||||
extension
|
||||
.AddStrExpression("ObjectVarToJSON",
|
||||
@@ -91,6 +94,7 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
.AddParameter("objectPtr", _("The object with the variable"))
|
||||
.AddParameter("objectvar", _("The object variable to be stringified"));
|
||||
|
||||
// Deprecated
|
||||
extension
|
||||
.AddAction(
|
||||
"JSONToVariableStructure",
|
||||
@@ -102,8 +106,10 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
"res/actions/net.png")
|
||||
.AddParameter("string", _("JSON string"))
|
||||
.AddParameter("scenevar", _("Variable where store the JSON object"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetHidden();
|
||||
|
||||
// Deprecated
|
||||
extension
|
||||
.AddAction("JSONToGlobalVariableStructure",
|
||||
_("Convert JSON to global variable"),
|
||||
@@ -116,6 +122,20 @@ BuiltinExtensionsImplementer::ImplementsCommonConversionsExtension(
|
||||
.AddParameter("string", _("JSON string"))
|
||||
.AddParameter("globalvar",
|
||||
_("Global variable where store the JSON object"))
|
||||
.MarkAsAdvanced()
|
||||
.SetHidden();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"JSONToVariableStructure2",
|
||||
_("Convert JSON to a variable"),
|
||||
_("Parse a JSON object and store it into a variable"),
|
||||
_("Convert JSON string _PARAM0_ and store it into variable _PARAM1_"),
|
||||
"",
|
||||
"res/actions/net24.png",
|
||||
"res/actions/net.png")
|
||||
.AddParameter("string", _("JSON string"))
|
||||
.AddParameter("variable", _("Variable where to store the JSON object"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
|
@@ -98,6 +98,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
|
||||
.AddParameter("string", _("Group"))
|
||||
.AddParameter("string", _("Text"));
|
||||
|
||||
// Deprecated
|
||||
extension
|
||||
.AddAction(
|
||||
"LireFichierExp",
|
||||
@@ -114,8 +115,27 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
|
||||
.AddParameter("string", _("Storage name"))
|
||||
.AddParameter("string", _("Group"))
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("scenevar", _("Scene variables"));
|
||||
.AddParameter("scenevar", _("Scene variable"))
|
||||
.SetHidden();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"ReadNumberFromStorage",
|
||||
_("Load a value"),
|
||||
_("Load the value saved in the specified element and store it in a "
|
||||
"variable.\nSpecify the structure leading to the element using / "
|
||||
"(example : Root/Level/Current)\nSpaces are forbidden in element "
|
||||
"names."),
|
||||
_("Load _PARAM1_ from storage _PARAM0_ and store value in _PARAM3_"),
|
||||
"",
|
||||
"res/actions/fichier24.png",
|
||||
"res/actions/fichier.png")
|
||||
.AddParameter("string", _("Storage name"))
|
||||
.AddParameter("string", _("Group"))
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("variable", _("Variable"));
|
||||
|
||||
// Deprecated
|
||||
extension
|
||||
.AddAction(
|
||||
"LireFichierTxt",
|
||||
@@ -133,7 +153,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsFileExtension(
|
||||
.AddParameter("string", _("Storage name"))
|
||||
.AddParameter("string", _("Group"))
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("scenevar", _("Scene variables"));
|
||||
.AddParameter("scenevar", _("Scene variable"))
|
||||
.SetHidden();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"ReadStringFromStorage",
|
||||
_("Load a text"),
|
||||
_("Load the text saved in the specified element and store it in a "
|
||||
"variable.\nSpecify the structure leading to the element using / "
|
||||
"(example : Root/Level/Current)\nSpaces are forbidden in element "
|
||||
"names."),
|
||||
_("Load _PARAM1_ from storage _PARAM0_ and store as text in "
|
||||
"_PARAM3_"),
|
||||
"",
|
||||
"res/actions/fichier24.png",
|
||||
"res/actions/fichier.png")
|
||||
.AddParameter("string", _("Storage name"))
|
||||
.AddParameter("string", _("Group"))
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
.AddParameter("variable", _("Variable"));
|
||||
|
||||
extension
|
||||
.AddAction("DeleteGroupFichier",
|
||||
|
@@ -64,9 +64,7 @@ void SpriteObject::ExposeResources(gd::ArbitraryResourceWorker& worker) {
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
SpriteObject::GetInitialInstanceProperties(
|
||||
const gd::InitialInstance& initialInstance,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) {
|
||||
const gd::InitialInstance& initialInstance) {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties["animation"] =
|
||||
gd::PropertyDescriptor(
|
||||
@@ -80,9 +78,7 @@ SpriteObject::GetInitialInstanceProperties(
|
||||
bool SpriteObject::UpdateInitialInstanceProperty(
|
||||
gd::InitialInstance& initialInstance,
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) {
|
||||
const gd::String& value) {
|
||||
if (name == "animation") {
|
||||
initialInstance.SetRawDoubleProperty(
|
||||
"animation", std::max(0, value.empty() ? 0 : value.To<int>()));
|
||||
|
@@ -47,14 +47,10 @@ class GD_CORE_API SpriteObject : public gd::ObjectConfiguration {
|
||||
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
|
||||
const gd::InitialInstance& position,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) override;
|
||||
const gd::InitialInstance& position) override;
|
||||
bool UpdateInitialInstanceProperty(gd::InitialInstance& position,
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) override;
|
||||
const gd::String& value) override;
|
||||
|
||||
/**
|
||||
* \brief Return the animation configuration.
|
||||
|
@@ -25,29 +25,271 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
extension.AddInstructionOrExpressionGroupMetadata(_("Variables"))
|
||||
.SetIcon("res/conditions/var24.png");
|
||||
|
||||
extension
|
||||
.AddCondition("NumberVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the number value of a variable."),
|
||||
_("The variable _PARAM0_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddCondition("StringVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the text (string) of a variable."),
|
||||
_("The variable _PARAM0_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"BooleanVariable",
|
||||
_("Variable value"),
|
||||
_("Compare the boolean value of a variable."),
|
||||
_("The variable _PARAM0_ is _PARAM1_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("trueorfalse", "");
|
||||
|
||||
extension
|
||||
.AddAction("SetNumberVariable",
|
||||
_("Change variable value"),
|
||||
_("Modify the number value of a variable."),
|
||||
_("the variable _PARAM0_"),
|
||||
"",
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddAction("SetStringVariable",
|
||||
_("Change text variable"),
|
||||
_("Modify the text (string) of a variable."),
|
||||
_("the variable _PARAM0_"),
|
||||
"",
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"SetBooleanVariable",
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of a variable."),
|
||||
_("Change the variable _PARAM0_: _PARAM1_"),
|
||||
"",
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.AddParameter("operator", _("Value"), "boolean")
|
||||
// This parameter allows to keep the operand expression
|
||||
// when the editor switch between variable instructions.
|
||||
.AddCodeOnlyParameter("trueorfalse", "");
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
"VariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in an array variable."),
|
||||
_("The number of children in the array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("VariableChildExists2",
|
||||
_("Child existence"),
|
||||
_("Check if the specified child of the structure "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of variable _PARAM0_ exists"),
|
||||
_("Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("variable", _("Variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"RemoveVariableChild",
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a structure variable."),
|
||||
_("Remove child _PARAM1_ from structure variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("ClearVariableChildren",
|
||||
_("Clear children"),
|
||||
_("Remove all the children from the structure or array "
|
||||
"variable."),
|
||||
_("Clear children from variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Structure or array variable"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("PushVariable",
|
||||
_("Add existing variable"),
|
||||
_("Adds an existing variable at the end of an array "
|
||||
"variable."),
|
||||
_("Add variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("variable", _("Variable with the content to add"))
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and added at the "
|
||||
"end of the array."))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
"PushString",
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) at the end of a array variable."),
|
||||
_("Add the value _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("PushNumber",
|
||||
_("Add variable array value"),
|
||||
_("Adds a number at the end of an array variable."),
|
||||
_("Add the value _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("PushBoolean",
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean at the end of an array variable."),
|
||||
_("Add the value _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddAction("RemoveVariableAt",
|
||||
_("Remove variable by index"),
|
||||
_("Removes a variable at the specified index of an array "
|
||||
"variable."),
|
||||
_("Remove variable at index _PARAM1_ from array "
|
||||
"variable _PARAM0_"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
"VariableFirstString",
|
||||
_("First text child"),
|
||||
_("Get the value of the first element of an array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"));
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"VariableFirstNumber",
|
||||
_("First number child"),
|
||||
_("Get the value of the first element of an array variable, if "
|
||||
"it is a number."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"));
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
"VariableLastString",
|
||||
_("Last text child"),
|
||||
_("Get the value of the last element of an array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"));
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
"VariableLastNumber",
|
||||
_("Last number child"),
|
||||
_("Get the value of the last element of an array variable, if "
|
||||
"it is a number."),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("variable", _("Array variable"));
|
||||
|
||||
// Legacy instructions
|
||||
|
||||
extension
|
||||
.AddCondition("VarScene",
|
||||
_("Number variable"),
|
||||
_("Compare the number value of a scene variable."),
|
||||
_("The number of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions());
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition("VarSceneTxt",
|
||||
_("Text variable"),
|
||||
_("Compare the text (string) of a scene variable."),
|
||||
_("The text of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions());
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition(
|
||||
@@ -55,12 +297,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of a scene variable."),
|
||||
_("The boolean value of scene variable _PARAM0_ is _PARAM1_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true");
|
||||
.SetDefaultValue("true")
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition("VariableChildExists",
|
||||
@@ -68,11 +311,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Check if the specified child of the scene structure "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of scene variable _PARAM0_ exists"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -81,11 +325,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Check if the specified child of the global structure "
|
||||
"variable exists."),
|
||||
_("Child _PARAM1_ of global variable _PARAM0_ exists"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("string", _("Name of the child"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -93,7 +338,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"Variable defined",
|
||||
"Test if the scene variable exists.",
|
||||
"Scene variable _PARAM0_ is defined",
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
@@ -105,12 +350,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Number variable"),
|
||||
_("Compare the number value of a global variable."),
|
||||
_("the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -118,12 +364,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Text variable"),
|
||||
_("Compare the text (string) of a global variable."),
|
||||
_("the text of the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"string", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -132,19 +379,20 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Boolean variable"),
|
||||
_("Compare the boolean value of a global variable."),
|
||||
_("The boolean value of global variable _PARAM0_ is _PARAM1_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("Check if the value is"))
|
||||
.SetDefaultValue("true");
|
||||
.SetDefaultValue("true")
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddCondition("VarGlobalDef",
|
||||
"Variable defined",
|
||||
"Test if a global variable exists.",
|
||||
"Global variable _PARAM0_ is defined",
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddCodeOnlyParameter("currentScene", "")
|
||||
@@ -157,24 +405,26 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of a scene variable."),
|
||||
_("the scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ModVarSceneTxt",
|
||||
_("Change text variable"),
|
||||
_("Modify the text (string) of a scene variable."),
|
||||
_("the text of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions());
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -182,11 +432,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of a scene variable."),
|
||||
_("Set the boolean value of scene variable _PARAM0_ to _PARAM1_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("New Value:"));
|
||||
.AddParameter("trueorfalse", _("New Value:"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ToggleSceneVariableAsBoolean",
|
||||
@@ -195,22 +446,24 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("If it was true, it will become false, and if it was "
|
||||
"false it will become true."),
|
||||
_("Toggle the boolean value of scene variable _PARAM0_"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"));
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ModVarGlobal",
|
||||
_("Change number variable"),
|
||||
_("Modify the number value of a global variable."),
|
||||
_("the global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("number",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -218,12 +471,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change text variable"),
|
||||
_("Modify the text (string) of a global variable."),
|
||||
_("the text of global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.UseStandardOperatorParameters("string",
|
||||
ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -232,11 +486,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Change boolean variable"),
|
||||
_("Modify the boolean value of a global variable."),
|
||||
_("Set the boolean value of global variable _PARAM0_ to _PARAM1_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.AddParameter("trueorfalse", _("New Value:"));
|
||||
.AddParameter("trueorfalse", _("New Value:"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("ToggleGlobalVariableAsBoolean",
|
||||
@@ -245,10 +500,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("If it was true, it will become false, and if it was "
|
||||
"false it will become true."),
|
||||
_("Toggle the boolean value of global variable _PARAM0_"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"));
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -256,12 +512,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a scene structure variable."),
|
||||
_("Remove child _PARAM1_ from scene structure variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -269,12 +526,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove a child"),
|
||||
_("Remove a child from a global structure variable."),
|
||||
_("Remove child _PARAM1_ from global structure variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Structure variable"))
|
||||
.AddParameter("string", _("Child's name"))
|
||||
.MarkAsAdvanced();
|
||||
.MarkAsAdvanced()
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction("VariableClearChildren",
|
||||
@@ -282,10 +540,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove all the children from the scene structure or array "
|
||||
"variable."),
|
||||
_("Clear children from scene variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Structure or array variable"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -294,10 +553,11 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Remove all the children from the global structure or array "
|
||||
"variable."),
|
||||
_("Clear children from global variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Structure or array variable"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -306,7 +566,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Adds an existing variable at the end of a scene array "
|
||||
"variable."),
|
||||
_("Add variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
@@ -314,6 +574,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and added at the "
|
||||
"end of the array."))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -322,11 +583,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) at the end of a scene array variable."),
|
||||
_("Add text _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -334,11 +596,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add number variable"),
|
||||
_("Adds a number at the end of a scene array variable."),
|
||||
_("Add number _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -346,11 +609,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean at the end of a scene array variable."),
|
||||
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -360,11 +624,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"variable."),
|
||||
_("Remove variable at index _PARAM1_ from scene array "
|
||||
"variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -373,12 +638,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in a scene array variable."),
|
||||
_("The number of children in the array variable _PARAM0_"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -387,9 +653,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("First text child"),
|
||||
_("Get the value of the first element of a scene array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
@@ -397,9 +664,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("First number child"),
|
||||
_("Get the value of the first element of a scene array variable, if "
|
||||
"it is a number."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
@@ -407,9 +675,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last text child"),
|
||||
_("Get the value of the last element of a scene array variable, if "
|
||||
"it is a text (string)."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
@@ -417,9 +686,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last number child"),
|
||||
_("Get the value of the last element of a scene array variable, if "
|
||||
"it is a number."),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("External variables/Scene variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array variable"));
|
||||
.AddParameter("scenevar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddAction(
|
||||
@@ -427,7 +697,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add existing variable"),
|
||||
_("Adds an existing variable at the end of a global array variable."),
|
||||
_("Add variable _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
@@ -435,6 +705,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
.SetParameterLongDescription(
|
||||
_("The content of the variable will *be copied* and added at the "
|
||||
"end of the array."))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -444,11 +715,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
"array variable."),
|
||||
_("Remove variable at index _PARAM1_ from global array "
|
||||
"variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Index to remove"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -457,11 +729,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add text variable"),
|
||||
_("Adds a text (string) at the end of a global array variable."),
|
||||
_("Add text _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("string", _("Text to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -469,11 +742,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add number variable"),
|
||||
_("Adds a number at the end of a global array variable."),
|
||||
_("Add number _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("expression", _("Number to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -481,11 +755,12 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Add boolean variable"),
|
||||
_("Adds a boolean at the end of a global array variable."),
|
||||
_("Add boolean _PARAM1_ to array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var24.png",
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.AddParameter("trueorfalse", _("Boolean to add"))
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -494,12 +769,13 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Number of children"),
|
||||
_("Compare the number of children in a global array variable."),
|
||||
_("The number of children of the array variable _PARAM0_"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/conditions/var24.png",
|
||||
"res/conditions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.UseStandardRelationalOperatorParameters(
|
||||
"number", ParameterOptions::MakeNewOptions())
|
||||
.SetRelevantForFunctionEventsOnly()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
@@ -507,18 +783,20 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("First text child"),
|
||||
_("Value of the first element of a global array "
|
||||
"variable, if it is a text (string) variable."),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariableFirstNumber",
|
||||
_("First number child"),
|
||||
_("Value of the first element of a global array "
|
||||
"variable, if it is a number variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression(
|
||||
@@ -526,9 +804,10 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last text child"),
|
||||
_("Value of the last element of a global array variable, if "
|
||||
"it is a text (string) variable."),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression(
|
||||
@@ -536,59 +815,65 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsVariablesExtension(
|
||||
_("Last number child"),
|
||||
_("Value of the last element of a global array variable, if "
|
||||
"it is a number variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array variable"));
|
||||
.AddParameter("globalvar", _("Array variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Number of children in a global array or "
|
||||
"structure variable"),
|
||||
_("Global variables/Arrays and structures"),
|
||||
_("External variables/Global variables/Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Array or structure variable"));
|
||||
.AddParameter("globalvar", _("Array or structure variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("VariableChildCount",
|
||||
_("Number of children"),
|
||||
_("Number of children in a scene array or "
|
||||
"structure variable"),
|
||||
_("Scene variables/Arrays and structures"),
|
||||
_("Arrays and structures"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Array or structure variable"));
|
||||
.AddParameter("variable", _("Array or structure variable"), "AllowUndeclaredVariable");
|
||||
|
||||
extension
|
||||
.AddExpression("Variable",
|
||||
_("Number variable"),
|
||||
_("Number value of a scene variable"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"));
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression("VariableString",
|
||||
_("Text variable"),
|
||||
_("Text of a scene variable"),
|
||||
_("Scene variables"),
|
||||
_("External variables/Scene variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("scenevar", _("Variable"));
|
||||
.AddParameter("scenevar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddExpression("GlobalVariable",
|
||||
_("Number variable"),
|
||||
_("Number value of a global variable"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Name of the global variable"));
|
||||
.AddParameter("globalvar", _("Name of the global variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
|
||||
extension
|
||||
.AddStrExpression("GlobalVariableString",
|
||||
_("Text variable"),
|
||||
_("Text of a global variable"),
|
||||
_("Global variables"),
|
||||
_("External variables/Global variables"),
|
||||
"res/actions/var.png")
|
||||
.AddParameter("globalvar", _("Variable"));
|
||||
.AddParameter("globalvar", _("Variable"))
|
||||
.SetRelevantForFunctionEventsOnly();
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -456,6 +456,15 @@ class GD_CORE_API InstructionMetadata : public gd::AbstractFunctionMetadata {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the type manipulated in a standard way by the instruction.
|
||||
*
|
||||
* \param type "number" or "string"
|
||||
*/
|
||||
const gd::String &GetManipulatedType() const {
|
||||
return codeExtraInformation.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* If InstructionMetadata::ExtraInformation::SetManipulatedType was called
|
||||
* with "number" or "string", this function will tell the code generator the
|
||||
|
@@ -96,11 +96,11 @@ std::shared_ptr<gd::PlatformExtension> Platform::GetExtension(
|
||||
std::unique_ptr<gd::ObjectConfiguration> Platform::CreateObjectConfiguration(
|
||||
gd::String type) const {
|
||||
if (creationFunctionTable.find(type) == creationFunctionTable.end()) {
|
||||
gd::LogWarning("Tried to create an object with an unknown type: " + type
|
||||
gd::LogWarning("Tried to create an object configuration with an unknown type: " + type
|
||||
+ " for platform " + GetName() + "!");
|
||||
type = "";
|
||||
if (creationFunctionTable.find("") == creationFunctionTable.end()) {
|
||||
gd::LogError("Unable to create a Base object!");
|
||||
gd::LogFatalError("Unable to create a base object configuration!");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ void EventBasedBehaviorBrowser::ExposeEvents(
|
||||
void EventBasedBehaviorBrowser::ExposeEvents(
|
||||
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) const {
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsBasedBehavior, worker);
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior, worker);
|
||||
}
|
||||
|
||||
void EventBasedBehaviorBrowser::ExposeObjects(
|
||||
|
@@ -29,8 +29,11 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API EventBasedBehaviorBrowser : public ProjectBrowser {
|
||||
public:
|
||||
EventBasedBehaviorBrowser(gd::EventsBasedBehavior &eventsBasedBehavior_)
|
||||
: eventsBasedBehavior(eventsBasedBehavior_) {}
|
||||
EventBasedBehaviorBrowser(
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension_,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior_)
|
||||
: eventsFunctionsExtension(eventsFunctionsExtension_),
|
||||
eventsBasedBehavior(eventsBasedBehavior_) {}
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
@@ -48,7 +51,7 @@ public:
|
||||
* This should be the preferred way to traverse all the events of an event-based behavior.
|
||||
*/
|
||||
void
|
||||
ExposeEvents(gd::Project &project,
|
||||
ExposeEvents(gd::Project &project,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) const override;
|
||||
|
||||
/**
|
||||
@@ -80,6 +83,7 @@ public:
|
||||
gd::ArbitraryBehaviorSharedDataWorker &worker) const override;
|
||||
|
||||
private:
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension;
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior;
|
||||
};
|
||||
|
||||
|
@@ -14,29 +14,27 @@
|
||||
#include "GDCore/Events/Expression.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
ArbitraryEventsWorker::~ArbitraryEventsWorker() {}
|
||||
AbstractArbitraryEventsWorker::~AbstractArbitraryEventsWorker() {}
|
||||
|
||||
void ArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
|
||||
void AbstractArbitraryEventsWorker::VisitEventList(gd::EventsList& events) {
|
||||
DoVisitEventList(events);
|
||||
|
||||
for (std::size_t i = 0; i < events.size();) {
|
||||
if (events[i].AcceptVisitor(*this))
|
||||
events.RemoveEvent(i);
|
||||
else {
|
||||
if (events[i].CanHaveSubEvents())
|
||||
VisitEventList(events[i].GetSubEvents());
|
||||
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
|
||||
bool AbstractArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
|
||||
bool shouldDelete = DoVisitEvent(event);
|
||||
if (shouldDelete) return true;
|
||||
|
||||
@@ -55,15 +53,17 @@ bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent& event) {
|
||||
*expressionAndMetadata.first, expressionAndMetadata.second);
|
||||
}
|
||||
|
||||
|
||||
if (!shouldDelete && event.CanHaveSubEvents()) {
|
||||
VisitEventList(event.GetSubEvents());
|
||||
}
|
||||
return shouldDelete;
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
|
||||
bool AbstractArbitraryEventsWorker::VisitLinkEvent(gd::LinkEvent& linkEvent) {
|
||||
return DoVisitLinkEvent(linkEvent);
|
||||
}
|
||||
|
||||
void ArbitraryEventsWorker::VisitInstructionList(
|
||||
void AbstractArbitraryEventsWorker::VisitInstructionList(
|
||||
gd::InstructionsList& instructions, bool areConditions) {
|
||||
DoVisitInstructionList(instructions, areConditions);
|
||||
|
||||
@@ -79,22 +79,19 @@ void ArbitraryEventsWorker::VisitInstructionList(
|
||||
}
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitInstruction(gd::Instruction& instruction,
|
||||
bool AbstractArbitraryEventsWorker::VisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
return DoVisitInstruction(instruction, isCondition);
|
||||
}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitEventExpression(gd::Expression& expression,
|
||||
bool AbstractArbitraryEventsWorker::VisitEventExpression(gd::Expression& expression,
|
||||
const gd::ParameterMetadata& metadata) {
|
||||
return DoVisitEventExpression(expression, metadata);
|
||||
}
|
||||
|
||||
ArbitraryEventsWorkerWithContext::~ArbitraryEventsWorkerWithContext() {}
|
||||
AbstractReadOnlyArbitraryEventsWorker::~AbstractReadOnlyArbitraryEventsWorker() {}
|
||||
|
||||
|
||||
ReadOnlyArbitraryEventsWorker::~ReadOnlyArbitraryEventsWorker() {}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events) {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events) {
|
||||
DoVisitEventList(events);
|
||||
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
@@ -109,7 +106,7 @@ void ReadOnlyArbitraryEventsWorker::VisitEventList(const gd::EventsList& events)
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
|
||||
DoVisitEvent(event);
|
||||
|
||||
const vector<const gd::InstructionsList*> conditionsVectors =
|
||||
@@ -130,11 +127,11 @@ void ReadOnlyArbitraryEventsWorker::VisitEvent(const gd::BaseEvent& event) {
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitLinkEvent(const gd::LinkEvent& linkEvent) {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitLinkEvent(const gd::LinkEvent& linkEvent) {
|
||||
DoVisitLinkEvent(linkEvent);
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitInstructionList(
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitInstructionList(
|
||||
const gd::InstructionsList& instructions, bool areConditions) {
|
||||
DoVisitInstructionList(instructions, areConditions);
|
||||
|
||||
@@ -150,21 +147,73 @@ void ReadOnlyArbitraryEventsWorker::VisitInstructionList(
|
||||
}
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& instruction,
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitInstruction(const gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
DoVisitInstruction(instruction, isCondition);
|
||||
}
|
||||
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEventExpression(const gd::Expression& expression,
|
||||
void AbstractReadOnlyArbitraryEventsWorker::VisitEventExpression(const gd::Expression& expression,
|
||||
const gd::ParameterMetadata& metadata) {
|
||||
DoVisitEventExpression(expression, metadata);
|
||||
}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::StopAnyEventIteration() {
|
||||
void AbstractReadOnlyArbitraryEventsWorker::StopAnyEventIteration() {
|
||||
shouldStopIteration = true;
|
||||
}
|
||||
|
||||
ArbitraryEventsWorker::~ArbitraryEventsWorker() {}
|
||||
|
||||
bool ArbitraryEventsWorker::VisitEvent(gd::BaseEvent &event) {
|
||||
return AbstractArbitraryEventsWorker::VisitEvent(event);
|
||||
}
|
||||
|
||||
ArbitraryEventsWorkerWithContext::~ArbitraryEventsWorkerWithContext() {}
|
||||
|
||||
bool ArbitraryEventsWorkerWithContext::VisitEvent(gd::BaseEvent &event) {
|
||||
if (!event.HasVariables()) {
|
||||
return AbstractArbitraryEventsWorker::VisitEvent(event);
|
||||
}
|
||||
// Push local variables
|
||||
auto newProjectScopedContainers =
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersWithLocalVariables(
|
||||
*currentProjectScopedContainers, event);
|
||||
auto *parentProjectScopedContainers = currentProjectScopedContainers;
|
||||
currentProjectScopedContainers = &newProjectScopedContainers;
|
||||
|
||||
bool shouldDelete = AbstractArbitraryEventsWorker::VisitEvent(event);
|
||||
|
||||
// Pop local variables
|
||||
currentProjectScopedContainers = parentProjectScopedContainers;
|
||||
return shouldDelete;
|
||||
}
|
||||
|
||||
ReadOnlyArbitraryEventsWorker::~ReadOnlyArbitraryEventsWorker() {}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorker::VisitEvent(
|
||||
const gd::BaseEvent &event) {
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
|
||||
}
|
||||
|
||||
ReadOnlyArbitraryEventsWorkerWithContext::~ReadOnlyArbitraryEventsWorkerWithContext() {}
|
||||
|
||||
void ReadOnlyArbitraryEventsWorkerWithContext::VisitEvent(
|
||||
const gd::BaseEvent &event) {
|
||||
if (!event.HasVariables()) {
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
|
||||
return;
|
||||
}
|
||||
// Push local variables
|
||||
auto newProjectScopedContainers =
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersWithLocalVariables(
|
||||
*currentProjectScopedContainers, event);
|
||||
auto *parentProjectScopedContainers = currentProjectScopedContainers;
|
||||
currentProjectScopedContainers = &newProjectScopedContainers;
|
||||
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEvent(event);
|
||||
|
||||
// Pop local variables
|
||||
currentProjectScopedContainers = parentProjectScopedContainers;
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_ARBITRARYEVENTSWORKER_H
|
||||
#define GDCORE_ARBITRARYEVENTSWORKER_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -12,6 +12,7 @@
|
||||
#include "GDCore/Events/EventVisitor.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class BaseEvent;
|
||||
@@ -25,27 +26,24 @@ class ParameterMetadata;
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief ArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions) and do some work on them. Can be used to implement refactoring
|
||||
* for example.
|
||||
* \brief AbstractArbitraryEventsWorker is a base abstract class used to browse events (and
|
||||
* instructions) and do some work on them. It must not be inherited directly.
|
||||
*
|
||||
* \see gd::ArbitraryEventsWorker
|
||||
* \see gd::ArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
|
||||
class GD_CORE_API AbstractArbitraryEventsWorker : private EventVisitor {
|
||||
public:
|
||||
ArbitraryEventsWorker(){};
|
||||
virtual ~ArbitraryEventsWorker();
|
||||
AbstractArbitraryEventsWorker(){};
|
||||
virtual ~AbstractArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(gd::EventsList& events) { VisitEventList(events); };
|
||||
protected:
|
||||
virtual bool VisitEvent(gd::BaseEvent& event) override;
|
||||
void VisitEventList(gd::EventsList& events);
|
||||
|
||||
private:
|
||||
void VisitEventList(gd::EventsList& events);
|
||||
bool VisitEvent(gd::BaseEvent& event) override;
|
||||
bool VisitLinkEvent(gd::LinkEvent& linkEvent) override;
|
||||
void VisitInstructionList(gd::InstructionsList& instructions,
|
||||
bool areConditions);
|
||||
@@ -101,6 +99,31 @@ class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions) and do some work on them. Can be used to implement refactoring
|
||||
* for example.
|
||||
*
|
||||
* \see gd::ArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryEventsWorker : public AbstractArbitraryEventsWorker {
|
||||
public:
|
||||
ArbitraryEventsWorker(){};
|
||||
virtual ~ArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(gd::EventsList &events) {
|
||||
AbstractArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
private:
|
||||
bool VisitEvent(gd::BaseEvent &event) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An events worker that will know about the context (the objects
|
||||
* container). Useful for workers working on expressions notably.
|
||||
@@ -110,10 +133,10 @@ class GD_CORE_API ArbitraryEventsWorker : private EventVisitor {
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ArbitraryEventsWorkerWithContext
|
||||
: public ArbitraryEventsWorker {
|
||||
: public AbstractArbitraryEventsWorker {
|
||||
public:
|
||||
ArbitraryEventsWorkerWithContext()
|
||||
: projectScopedContainers(nullptr){};
|
||||
: currentProjectScopedContainers(nullptr){};
|
||||
virtual ~ArbitraryEventsWorkerWithContext();
|
||||
|
||||
/**
|
||||
@@ -121,53 +144,50 @@ class GD_CORE_API ArbitraryEventsWorkerWithContext
|
||||
* giving the objects container on which the events are applying to.
|
||||
*/
|
||||
void Launch(gd::EventsList& events,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_) {
|
||||
projectScopedContainers = &projectScopedContainers_;
|
||||
ArbitraryEventsWorker::Launch(events);
|
||||
const gd::ProjectScopedContainers& projectScopedContainers) {
|
||||
currentProjectScopedContainers = &projectScopedContainers;
|
||||
AbstractArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
void Launch(gd::EventsList& events) = delete;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
|
||||
// Pointers are guaranteed to be not nullptr after
|
||||
// Launch was called.
|
||||
return *projectScopedContainers;
|
||||
return *currentProjectScopedContainers;
|
||||
};
|
||||
const gd::ObjectsContainersList& GetObjectsContainersList() {
|
||||
// Pointers are guaranteed to be not nullptr after
|
||||
// Launch was called.
|
||||
return projectScopedContainers->GetObjectsContainersList();
|
||||
return currentProjectScopedContainers->GetObjectsContainersList();
|
||||
};
|
||||
|
||||
private:
|
||||
const gd::ProjectScopedContainers* projectScopedContainers;
|
||||
bool VisitEvent(gd::BaseEvent& event) override;
|
||||
|
||||
const gd::ProjectScopedContainers* currentProjectScopedContainers;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ReadOnlyArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions). It can be used to implement autocompletion for example.
|
||||
* instructions). It must not be inherited directly.
|
||||
*
|
||||
* \see gd::ReadOnlyArbitraryEventsWorker
|
||||
* \see gd::ReadOnlyArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
|
||||
class GD_CORE_API AbstractReadOnlyArbitraryEventsWorker : private ReadOnlyEventVisitor {
|
||||
public:
|
||||
ReadOnlyArbitraryEventsWorker() : shouldStopIteration(false) {};
|
||||
virtual ~ReadOnlyArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(const gd::EventsList& events) { VisitEventList(events); };
|
||||
AbstractReadOnlyArbitraryEventsWorker() : shouldStopIteration(false) {};
|
||||
virtual ~AbstractReadOnlyArbitraryEventsWorker();
|
||||
|
||||
protected:
|
||||
void StopAnyEventIteration() override;
|
||||
virtual void VisitEvent(const gd::BaseEvent& event) override;
|
||||
|
||||
void VisitEventList(const gd::EventsList& events);
|
||||
|
||||
private:
|
||||
void VisitEventList(const gd::EventsList& events);
|
||||
void VisitEvent(const gd::BaseEvent& event) override;
|
||||
void VisitLinkEvent(const gd::LinkEvent& linkEvent) override;
|
||||
void VisitInstructionList(const gd::InstructionsList& instructions,
|
||||
bool areConditions);
|
||||
@@ -213,6 +233,31 @@ protected:
|
||||
bool shouldStopIteration;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief ReadOnlyArbitraryEventsWorker is an abstract class used to browse events (and
|
||||
* instructions). It can be used to implement autocompletion for example.
|
||||
*
|
||||
* \see gd::ReadOnlyArbitraryEventsWorkerWithContext
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorker
|
||||
: public AbstractReadOnlyArbitraryEventsWorker {
|
||||
public:
|
||||
ReadOnlyArbitraryEventsWorker(){};
|
||||
virtual ~ReadOnlyArbitraryEventsWorker();
|
||||
|
||||
/**
|
||||
* \brief Launch the worker on the specified events list.
|
||||
*/
|
||||
void Launch(const gd::EventsList &events) {
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
private:
|
||||
void VisitEvent(const gd::BaseEvent &event) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief An events worker that will know about the context (the objects
|
||||
* container). Useful for workers working on expressions notably.
|
||||
@@ -222,10 +267,10 @@ protected:
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API ReadOnlyArbitraryEventsWorkerWithContext
|
||||
: public ReadOnlyArbitraryEventsWorker {
|
||||
: public AbstractReadOnlyArbitraryEventsWorker {
|
||||
public:
|
||||
ReadOnlyArbitraryEventsWorkerWithContext()
|
||||
: projectScopedContainers(nullptr){};
|
||||
: currentProjectScopedContainers(nullptr){};
|
||||
virtual ~ReadOnlyArbitraryEventsWorkerWithContext();
|
||||
|
||||
/**
|
||||
@@ -233,24 +278,22 @@ class GD_CORE_API ReadOnlyArbitraryEventsWorkerWithContext
|
||||
* giving the objects container on which the events are applying to.
|
||||
*/
|
||||
void Launch(const gd::EventsList& events,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_) {
|
||||
projectScopedContainers = &projectScopedContainers_;
|
||||
ReadOnlyArbitraryEventsWorker::Launch(events);
|
||||
const gd::ProjectScopedContainers& projectScopedContainers) {
|
||||
currentProjectScopedContainers = &projectScopedContainers;
|
||||
AbstractReadOnlyArbitraryEventsWorker::VisitEventList(events);
|
||||
};
|
||||
|
||||
void Launch(gd::EventsList& events) = delete;
|
||||
|
||||
protected:
|
||||
protected:
|
||||
const gd::ProjectScopedContainers& GetProjectScopedContainers() {
|
||||
// Pointers are guaranteed to be not nullptr after
|
||||
// Launch was called.
|
||||
return *projectScopedContainers;
|
||||
return *currentProjectScopedContainers;
|
||||
};
|
||||
|
||||
private:
|
||||
const gd::ProjectScopedContainers* projectScopedContainers;
|
||||
void VisitEvent(const gd::BaseEvent& event) override;
|
||||
|
||||
const gd::ProjectScopedContainers* currentProjectScopedContainers;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_ARBITRARYEVENTSWORKER_H
|
||||
|
65
Core/GDCore/IDE/Events/BehaviorParametersFiller.cpp
Normal file
65
Core/GDCore/IDE/Events/BehaviorParametersFiller.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2024 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "BehaviorParametersFiller.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool BehaviorParametersFiller::DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) {
|
||||
const auto &metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
instruction.GetParameters(), metadata.GetParameters(),
|
||||
[&](const gd::ParameterMetadata ¶meterMetadata,
|
||||
const gd::Expression ¶meterValue, size_t parameterIndex,
|
||||
const gd::String &lastObjectName) {
|
||||
if (parameterMetadata.GetValueTypeMetadata().IsBehavior() &&
|
||||
parameterValue.GetPlainString().length() == 0) {
|
||||
|
||||
auto &expectedBehaviorTypeName =
|
||||
parameterMetadata.GetValueTypeMetadata().GetExtraInfo();
|
||||
|
||||
auto &objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
auto behaviorNames =
|
||||
objectsContainersList.GetBehaviorsOfObject(lastObjectName, true);
|
||||
|
||||
gd::String foundBehaviorName = "";
|
||||
for (auto &behaviorName : behaviorNames) {
|
||||
auto behaviorTypeName =
|
||||
objectsContainersList.GetTypeOfBehavior(behaviorName, false);
|
||||
if (behaviorTypeName == expectedBehaviorTypeName) {
|
||||
foundBehaviorName = behaviorName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!foundBehaviorName.empty()) {
|
||||
instruction.SetParameter(parameterIndex,
|
||||
gd::Expression(foundBehaviorName));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
BehaviorParametersFiller::~BehaviorParametersFiller() {}
|
||||
|
||||
} // namespace gd
|
45
Core/GDCore/IDE/Events/BehaviorParametersFiller.h
Normal file
45
Core/GDCore/IDE/Events/BehaviorParametersFiller.h
Normal file
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2024 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class Platform;
|
||||
class ProjectScopedContainers;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Fill empty behavior parameters with any behavior that matches the
|
||||
* required behavior type.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API BehaviorParametersFiller : public ArbitraryEventsWorker {
|
||||
public:
|
||||
BehaviorParametersFiller(
|
||||
const gd::Platform &platform_,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers_)
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_){};
|
||||
virtual ~BehaviorParametersFiller();
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::ProjectScopedContainers &projectScopedContainers;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -296,7 +296,7 @@ class GD_CORE_API ExpressionObjectFinder : public ExpressionParser2NodeWorker {
|
||||
};
|
||||
|
||||
bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& actions,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
@@ -347,7 +347,7 @@ bool EventsRefactorer::RenameObjectInActions(const gd::Platform& platform,
|
||||
|
||||
bool EventsRefactorer::RenameObjectInConditions(
|
||||
const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& conditions,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
@@ -399,7 +399,7 @@ bool EventsRefactorer::RenameObjectInConditions(
|
||||
|
||||
bool EventsRefactorer::RenameObjectInEventParameters(
|
||||
const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::Expression& expression,
|
||||
gd::ParameterMetadata parameterMetadata,
|
||||
gd::String oldName,
|
||||
@@ -432,7 +432,7 @@ bool EventsRefactorer::RenameObjectInEventParameters(
|
||||
}
|
||||
|
||||
void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::EventsList& events,
|
||||
gd::String oldName,
|
||||
gd::String newName) {
|
||||
@@ -475,7 +475,7 @@ void EventsRefactorer::RenameObjectInEvents(const gd::Platform& platform,
|
||||
}
|
||||
|
||||
bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& actions,
|
||||
gd::String name) {
|
||||
bool somethingModified = false;
|
||||
@@ -532,7 +532,7 @@ bool EventsRefactorer::RemoveObjectInActions(const gd::Platform& platform,
|
||||
|
||||
bool EventsRefactorer::RemoveObjectInConditions(
|
||||
const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& conditions,
|
||||
gd::String name) {
|
||||
bool somethingModified = false;
|
||||
@@ -588,31 +588,6 @@ bool EventsRefactorer::RemoveObjectInConditions(
|
||||
return somethingModified;
|
||||
}
|
||||
|
||||
void EventsRefactorer::RemoveObjectInEvents(const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::EventsList& events,
|
||||
gd::String name) {
|
||||
for (std::size_t i = 0; i < events.size(); ++i) {
|
||||
vector<gd::InstructionsList*> conditionsVectors =
|
||||
events[i].GetAllConditionsVectors();
|
||||
for (std::size_t j = 0; j < conditionsVectors.size(); ++j) {
|
||||
bool conditionsModified = RemoveObjectInConditions(
|
||||
platform, projectScopedContainers, *conditionsVectors[j], name);
|
||||
}
|
||||
|
||||
vector<gd::InstructionsList*> actionsVectors =
|
||||
events[i].GetAllActionsVectors();
|
||||
for (std::size_t j = 0; j < actionsVectors.size(); ++j) {
|
||||
bool actionsModified = RemoveObjectInActions(
|
||||
platform, projectScopedContainers, *actionsVectors[j], name);
|
||||
}
|
||||
|
||||
if (events[i].CanHaveSubEvents())
|
||||
RemoveObjectInEvents(
|
||||
platform, projectScopedContainers, events[i].GetSubEvents(), name);
|
||||
}
|
||||
}
|
||||
|
||||
gd::String ReplaceAllOccurrencesCaseInsensitive(gd::String context,
|
||||
const gd::String& from,
|
||||
const gd::String& to) {
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EVENTSREFACTORER_H
|
||||
#define GDCORE_EVENTSREFACTORER_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@@ -81,19 +81,11 @@ class GD_CORE_API EventsRefactorer {
|
||||
* events ).
|
||||
*/
|
||||
static void RenameObjectInEvents(const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::EventsList& events,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
|
||||
/**
|
||||
* Remove all actions or conditions using an object
|
||||
*/
|
||||
static void RemoveObjectInEvents(const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::EventsList& events,
|
||||
gd::String name);
|
||||
|
||||
/**
|
||||
* Search for a gd::String in events
|
||||
*
|
||||
@@ -136,7 +128,7 @@ class GD_CORE_API EventsRefactorer {
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RenameObjectInActions(const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& instructions,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
@@ -148,7 +140,7 @@ class GD_CORE_API EventsRefactorer {
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RenameObjectInConditions(const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& instructions,
|
||||
gd::String oldName,
|
||||
gd::String newName);
|
||||
@@ -161,7 +153,7 @@ class GD_CORE_API EventsRefactorer {
|
||||
*/
|
||||
static bool RenameObjectInEventParameters(
|
||||
const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::Expression& expression,
|
||||
gd::ParameterMetadata parameterMetadata,
|
||||
gd::String oldName,
|
||||
@@ -173,7 +165,7 @@ class GD_CORE_API EventsRefactorer {
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RemoveObjectInConditions(const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& conditions,
|
||||
gd::String name);
|
||||
|
||||
@@ -183,7 +175,7 @@ class GD_CORE_API EventsRefactorer {
|
||||
* \return true if something was modified.
|
||||
*/
|
||||
static bool RemoveObjectInActions(const gd::Platform& platform,
|
||||
gd::ProjectScopedContainers& projectScopedContainers,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::InstructionsList& conditions,
|
||||
gd::String name);
|
||||
|
||||
@@ -250,5 +242,3 @@ class GD_CORE_API EventsRefactorer {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EVENTSREFACTORER_H
|
||||
|
100
Core/GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.cpp
Normal file
100
Core/GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.h"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodePrinter.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableNameFinder.h"
|
||||
#include "GDCore/IDE/VariableInstructionSwitcher.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
bool EventsVariableInstructionTypeSwitcher::DoVisitInstruction(gd::Instruction& instruction,
|
||||
bool isCondition) {
|
||||
const auto& metadata = isCondition
|
||||
? gd::MetadataProvider::GetConditionMetadata(
|
||||
platform, instruction.GetType())
|
||||
: gd::MetadataProvider::GetActionMetadata(
|
||||
platform, instruction.GetType());
|
||||
|
||||
gd::ParameterMetadataTools::IterateOverParametersWithIndex(
|
||||
instruction.GetParameters(),
|
||||
metadata.GetParameters(),
|
||||
[&](const gd::ParameterMetadata& parameterMetadata,
|
||||
const gd::Expression& parameterValue,
|
||||
size_t parameterIndex,
|
||||
const gd::String& lastObjectName) {
|
||||
const gd::String& type = parameterMetadata.GetType();
|
||||
|
||||
if (!gd::ParameterMetadata::IsExpression("variable", type) ||
|
||||
!gd::VariableInstructionSwitcher::IsSwitchableVariableInstruction(
|
||||
instruction.GetType())) {
|
||||
return;
|
||||
}
|
||||
const auto variableName =
|
||||
gd::ExpressionVariableNameFinder::GetVariableName(
|
||||
*parameterValue.GetRootNode());
|
||||
|
||||
const gd::VariablesContainer *variablesContainer = nullptr;
|
||||
if (type == "objectvar") {
|
||||
const auto &objectsContainersList =
|
||||
GetProjectScopedContainers().GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(
|
||||
lastObjectName, variableName) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variablesContainer =
|
||||
GetProjectScopedContainers()
|
||||
.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(lastObjectName);
|
||||
}
|
||||
} else {
|
||||
if (GetProjectScopedContainers().GetVariablesContainersList().Has(
|
||||
variableName)) {
|
||||
variablesContainer =
|
||||
&GetProjectScopedContainers()
|
||||
.GetVariablesContainersList()
|
||||
.GetVariablesContainerFromVariableName(variableName);
|
||||
}
|
||||
}
|
||||
|
||||
// Every occurrence of the variable or its children are checked.
|
||||
// Ensuring that a child is actually the one with a type change would
|
||||
// take more time.
|
||||
if (variablesContainer == &targetVariablesContainer) {
|
||||
if (typeChangedVariableNames.find(variableName) !=
|
||||
typeChangedVariableNames.end()) {
|
||||
gd::VariableInstructionSwitcher::
|
||||
SwitchBetweenUnifiedInstructionIfNeeded(
|
||||
platform, GetProjectScopedContainers(), instruction);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
EventsVariableInstructionTypeSwitcher::~EventsVariableInstructionTypeSwitcher() {}
|
||||
|
||||
} // namespace gd
|
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2024 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class VariablesContainer;
|
||||
class Platform;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* \brief Switch the types of variable instructions for a given set of
|
||||
* variables.
|
||||
*
|
||||
* \see gd::VariableInstructionSwitcher
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class GD_CORE_API EventsVariableInstructionTypeSwitcher
|
||||
: public ArbitraryEventsWorkerWithContext {
|
||||
public:
|
||||
EventsVariableInstructionTypeSwitcher(
|
||||
const gd::Platform &platform_,
|
||||
const gd::VariablesContainer &targetVariablesContainer_,
|
||||
const std::unordered_set<gd::String> &typeChangedVariableNames_)
|
||||
: platform(platform_),
|
||||
targetVariablesContainer(targetVariablesContainer_),
|
||||
typeChangedVariableNames(typeChangedVariableNames_){};
|
||||
virtual ~EventsVariableInstructionTypeSwitcher();
|
||||
|
||||
private:
|
||||
bool DoVisitInstruction(gd::Instruction &instruction,
|
||||
bool isCondition) override;
|
||||
|
||||
const gd::Platform &platform;
|
||||
const gd::VariablesContainer &targetVariablesContainer;
|
||||
gd::String objectName;
|
||||
const std::unordered_set<gd::String> &typeChangedVariableNames;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -20,6 +20,9 @@
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadataTools.h"
|
||||
#include "GDCore/IDE/Events/ExpressionValidator.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableNameFinder.h"
|
||||
#include "GDCore/IDE/VariableInstructionSwitcher.h"
|
||||
#include "GDCore/IDE/WholeProjectRefactorer.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
@@ -42,7 +45,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_,
|
||||
const gd::VariablesContainer& targetVariablesContainer_,
|
||||
const std::unordered_map<gd::String, gd::String>& oldToNewVariableNames_,
|
||||
const VariablesRenamingChangesetNode& variablesRenamingChangesetRoot_,
|
||||
const std::unordered_set<gd::String>& removedVariableNames_)
|
||||
: hasDoneRenaming(false),
|
||||
removedVariableUsed(false),
|
||||
@@ -50,7 +53,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
forcedInitialVariablesContainer(nullptr),
|
||||
targetVariablesContainer(targetVariablesContainer_),
|
||||
oldToNewVariableNames(oldToNewVariableNames_),
|
||||
variablesRenamingChangesetRoot(variablesRenamingChangesetRoot_),
|
||||
removedVariableNames(removedVariableNames_){};
|
||||
virtual ~ExpressionVariableReplacer(){};
|
||||
|
||||
@@ -80,20 +83,28 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
// will be accessed.
|
||||
|
||||
if (forcedInitialVariablesContainer) {
|
||||
const gd::String oldVariableName = node.name;
|
||||
PushVariablesRenamingChangesetRoot();
|
||||
// A scope was forced. Honor it: it means this node represents a variable
|
||||
// of the forced variables container.
|
||||
if (forcedInitialVariablesContainer == &targetVariablesContainer) {
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
|
||||
}
|
||||
|
||||
if (node.child) node.child->Visit(*this);
|
||||
if (node.child) {
|
||||
bool hasBeenPushed =
|
||||
PushVariablesRenamingChangesetNodeForVariable(oldVariableName);
|
||||
node.child->Visit(*this);
|
||||
PopVariablesRenamingChangesetNode(hasBeenPushed);
|
||||
}
|
||||
PopVariablesRenamingChangesetNode(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Match the potential *new* name of the variable, because refactorings are
|
||||
// done after changes in the variables container.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
GetPotentialNewName(node.name),
|
||||
node.name,
|
||||
[&]() {
|
||||
// This represents an object.
|
||||
// Remember the object name.
|
||||
@@ -103,14 +114,21 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
if (&projectScopedContainers.GetVariablesContainersList()
|
||||
.GetVariablesContainerFromVariableName(node.name) ==
|
||||
&targetVariablesContainer) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
|
||||
PushVariablesRenamingChangesetRoot();
|
||||
RenameVariableAndVisitChild(node.name, node.child.get());
|
||||
PopVariablesRenamingChangesetNode(true);
|
||||
} else {
|
||||
if (node.child) {
|
||||
PushVariablesRenamingChangesetNodeForIgnoredVariables();
|
||||
node.child->Visit(*this);
|
||||
PopVariablesRenamingChangesetNode(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (node.child) node.child->Visit(*this);
|
||||
},
|
||||
[&]() {
|
||||
// This is a property.
|
||||
@@ -121,14 +139,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
if (node.child) node.child->Visit(*this);
|
||||
},
|
||||
[&]() {
|
||||
// This is something else - potentially a deleted variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
|
||||
}
|
||||
|
||||
// This is something else.
|
||||
if (node.child) node.child->Visit(*this);
|
||||
});
|
||||
}
|
||||
@@ -136,25 +147,49 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
if (!objectNameToUseForVariableAccessor.empty()) {
|
||||
// This is always true because MatchIdentifierWithName is used to get
|
||||
// objectNameToUseForVariableAccessor.
|
||||
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
|
||||
objectNameToUseForVariableAccessor, targetVariablesContainer)) {
|
||||
objectNameToUseForVariableAccessor = "";
|
||||
// The node represents an object variable, and this object variables are
|
||||
// the target. Do the replacement or removals:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(node.name);
|
||||
PushVariablesRenamingChangesetRoot();
|
||||
RenameVariableAndVisitChild(node.name, node.child.get());
|
||||
PopVariablesRenamingChangesetNode(true);
|
||||
}
|
||||
} else {
|
||||
RenameVariableAndVisitChild(node.name, node.child.get());
|
||||
}
|
||||
objectNameToUseForVariableAccessor = "";
|
||||
|
||||
if (node.child) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
objectNameToUseForVariableAccessor = "";
|
||||
|
||||
// TODO Literal expressions could be checked to handle renaming in
|
||||
// `expression` and in `child`.
|
||||
node.expression->Visit(*this);
|
||||
if (node.child) node.child->Visit(*this);
|
||||
if (node.child) {
|
||||
PushVariablesRenamingChangesetNodeForIgnoredVariables();
|
||||
node.child->Visit(*this);
|
||||
PopVariablesRenamingChangesetNode(true);
|
||||
}
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
void OnVisitIdentifierNode(IdentifierNode &node) override {
|
||||
auto renameVariableAndChild = [this, &node]() {
|
||||
PushVariablesRenamingChangesetRoot();
|
||||
const gd::String oldVariableName = node.identifierName;
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(node.identifierName);
|
||||
if (!node.childIdentifierName.empty()) {
|
||||
bool hasBeenPushed =
|
||||
PushVariablesRenamingChangesetNodeForVariable(oldVariableName);
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(
|
||||
node.childIdentifierName);
|
||||
PopVariablesRenamingChangesetNode(hasBeenPushed);
|
||||
}
|
||||
PopVariablesRenamingChangesetNode(true);
|
||||
};
|
||||
|
||||
auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
|
||||
@@ -166,7 +201,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
// A scope was forced. Honor it: it means this node represents a variable
|
||||
// of the forced variables container.
|
||||
if (forcedInitialVariablesContainer == &targetVariablesContainer) {
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(node.identifierName);
|
||||
renameVariableAndChild();
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -174,25 +209,27 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
// Match the potential *new* name of the variable, because refactorings are
|
||||
// done after changes in the variables container.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
GetPotentialNewName(node.identifierName),
|
||||
node.identifierName,
|
||||
[&]() {
|
||||
// This represents an object.
|
||||
if (objectsContainersList.HasObjectOrGroupVariablesContainer(
|
||||
node.identifierName, targetVariablesContainer)) {
|
||||
// The node represents an object variable, and this object variables
|
||||
// are the target. Do the replacement or removals:
|
||||
PushVariablesRenamingChangesetRoot();
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(
|
||||
node.childIdentifierName);
|
||||
PopVariablesRenamingChangesetNode(true);
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
if (&projectScopedContainers.GetVariablesContainersList()
|
||||
.GetVariablesContainerFromVariableName(
|
||||
node.identifierName) == &targetVariablesContainer) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(
|
||||
node.identifierName);
|
||||
renameVariableAndChild();
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
@@ -202,14 +239,7 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
// This is a parameter.
|
||||
},
|
||||
[&]() {
|
||||
// This is something else - potentially a deleted variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList()
|
||||
.HasVariablesContainer(targetVariablesContainer)) {
|
||||
// The node represents a variable, that can come from the target
|
||||
// (because the target is in the scope), replace or remove it:
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(
|
||||
node.identifierName);
|
||||
}
|
||||
// This is something else.
|
||||
});
|
||||
}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
@@ -268,19 +298,24 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
bool hasDoneRenaming;
|
||||
bool removedVariableUsed;
|
||||
|
||||
const gd::String& GetPotentialNewName(const gd::String& oldName) {
|
||||
return oldToNewVariableNames.count(oldName) >= 1
|
||||
? oldToNewVariableNames.find(oldName)->second
|
||||
: oldName;
|
||||
}
|
||||
|
||||
bool RenameOrRemoveVariableOfTargetVariableContainer(
|
||||
gd::String& variableName) {
|
||||
const auto *currentVariablesRenamingChangesetNode =
|
||||
GetCurrentVariablesRenamingChangesetNode();
|
||||
if (!currentVariablesRenamingChangesetNode) {
|
||||
return false;
|
||||
}
|
||||
const auto &oldToNewVariableNames =
|
||||
currentVariablesRenamingChangesetNode->oldToNewVariableNames;
|
||||
if (oldToNewVariableNames.count(variableName) >= 1) {
|
||||
variableName = oldToNewVariableNames.find(variableName)->second;
|
||||
hasDoneRenaming = true;
|
||||
return true;
|
||||
} else if (removedVariableNames.count(variableName) >= 1) {
|
||||
} else if (
|
||||
// Only the root variable is checked for removing.
|
||||
currentVariablesRenamingChangesetNode ==
|
||||
&variablesRenamingChangesetRoot &&
|
||||
removedVariableNames.count(variableName) >= 1) {
|
||||
removedVariableUsed = true;
|
||||
return true;
|
||||
}
|
||||
@@ -288,6 +323,62 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
return false; // Nothing was changed or done.
|
||||
}
|
||||
|
||||
void RenameVariableAndVisitChild(gd::String &variableName,
|
||||
ExpressionNode *childNode) {
|
||||
// `variableName` is modified by
|
||||
// `RenameOrRemoveVariableOfTargetVariableContainer`.
|
||||
const gd::String oldVariableName = variableName;
|
||||
RenameOrRemoveVariableOfTargetVariableContainer(variableName);
|
||||
if (childNode) {
|
||||
bool hasBeenPushed =
|
||||
PushVariablesRenamingChangesetNodeForVariable(oldVariableName);
|
||||
childNode->Visit(*this);
|
||||
PopVariablesRenamingChangesetNode(hasBeenPushed);
|
||||
}
|
||||
}
|
||||
|
||||
void PushVariablesRenamingChangesetRoot() {
|
||||
variablesRenamingChangesetNodeStack.push_back(&variablesRenamingChangesetRoot);
|
||||
}
|
||||
|
||||
void PushVariablesRenamingChangesetNodeForIgnoredVariables() {
|
||||
variablesRenamingChangesetNodeStack.push_back(nullptr);
|
||||
}
|
||||
|
||||
const gd::VariablesRenamingChangesetNode *GetCurrentVariablesRenamingChangesetNode() {
|
||||
return variablesRenamingChangesetNodeStack.size() == 0 ?
|
||||
&variablesRenamingChangesetRoot :
|
||||
variablesRenamingChangesetNodeStack
|
||||
[variablesRenamingChangesetNodeStack.size() - 1];
|
||||
}
|
||||
|
||||
bool PushVariablesRenamingChangesetNodeForVariable(const gd::String& variableName) {
|
||||
const auto *currentVariablesRenamingChangesetNode = GetCurrentVariablesRenamingChangesetNode();
|
||||
if (!currentVariablesRenamingChangesetNode) {
|
||||
// There were already no more change on a parent.
|
||||
return false;
|
||||
}
|
||||
const auto &childVariablesRenamingChangesetNodeItr =
|
||||
currentVariablesRenamingChangesetNode->modifiedVariables.find(
|
||||
variableName);
|
||||
if (childVariablesRenamingChangesetNodeItr ==
|
||||
currentVariablesRenamingChangesetNode->modifiedVariables.end()) {
|
||||
// There is no more change on the current variable child.
|
||||
variablesRenamingChangesetNodeStack.push_back(nullptr);
|
||||
}
|
||||
else {
|
||||
variablesRenamingChangesetNodeStack.push_back(
|
||||
childVariablesRenamingChangesetNodeItr->second.get());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PopVariablesRenamingChangesetNode(bool hasBeenPushed) {
|
||||
if (hasBeenPushed) {
|
||||
variablesRenamingChangesetNodeStack.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
// Scope:
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
@@ -295,10 +386,11 @@ class GD_CORE_API ExpressionVariableReplacer
|
||||
|
||||
// Renaming or removing to do:
|
||||
const gd::VariablesContainer& targetVariablesContainer;
|
||||
const std::unordered_map<gd::String, gd::String>& oldToNewVariableNames;
|
||||
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot;
|
||||
const std::unordered_set<gd::String>& removedVariableNames;
|
||||
|
||||
gd::String objectNameToUseForVariableAccessor;
|
||||
std::vector<const VariablesRenamingChangesetNode*> variablesRenamingChangesetNodeStack;
|
||||
};
|
||||
|
||||
const gd::VariablesContainer*
|
||||
@@ -351,7 +443,7 @@ bool EventsVariableReplacer::DoVisitInstruction(gd::Instruction& instruction,
|
||||
ExpressionVariableReplacer renamer(platform,
|
||||
GetProjectScopedContainers(),
|
||||
targetVariablesContainer,
|
||||
oldToNewVariableNames,
|
||||
variablesRenamingChangesetRoot,
|
||||
removedVariableNames);
|
||||
renamer.SetForcedInitialVariablesContainer(
|
||||
FindForcedVariablesContainerIfAny(type, lastObjectName));
|
||||
@@ -383,7 +475,7 @@ bool EventsVariableReplacer::DoVisitEventExpression(
|
||||
ExpressionVariableReplacer renamer(platform,
|
||||
GetProjectScopedContainers(),
|
||||
targetVariablesContainer,
|
||||
oldToNewVariableNames,
|
||||
variablesRenamingChangesetRoot,
|
||||
removedVariableNames);
|
||||
renamer.SetForcedInitialVariablesContainer(
|
||||
FindForcedVariablesContainerIfAny(type, ""));
|
||||
|
@@ -4,6 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
@@ -12,11 +13,13 @@
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
class VariablesContainer;
|
||||
class EventsList;
|
||||
class Platform;
|
||||
struct VariablesRenamingChangesetNode;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -33,12 +36,12 @@ class GD_CORE_API EventsVariableReplacer
|
||||
EventsVariableReplacer(
|
||||
const gd::Platform &platform_,
|
||||
const gd::VariablesContainer &targetVariablesContainer_,
|
||||
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames_,
|
||||
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot_,
|
||||
const std::unordered_set<gd::String> &removedVariableNames_)
|
||||
: platform(platform_),
|
||||
targetVariablesContainer(targetVariablesContainer_),
|
||||
oldToNewVariableNames(oldToNewVariableNames_),
|
||||
removedVariableNames(removedVariableNames_){};
|
||||
variablesRenamingChangesetRoot(variablesRenamingChangesetRoot_),
|
||||
removedVariableNames(removedVariableNames_) {};
|
||||
virtual ~EventsVariableReplacer();
|
||||
|
||||
private:
|
||||
@@ -53,7 +56,7 @@ class GD_CORE_API EventsVariableReplacer
|
||||
const gd::Platform &platform;
|
||||
const gd::VariablesContainer &targetVariablesContainer;
|
||||
gd::String objectName;
|
||||
const std::unordered_map<gd::String, gd::String> &oldToNewVariableNames;
|
||||
const VariablesRenamingChangesetNode &variablesRenamingChangesetRoot;
|
||||
const std::unordered_set<gd::String> &removedVariableNames;
|
||||
};
|
||||
|
||||
|
@@ -229,7 +229,7 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
|
||||
const gd::Platform& platform,
|
||||
const gd::Project& project,
|
||||
const gd::Layout& layout,
|
||||
const gd::Object& object) {
|
||||
const gd::String& objectName) {
|
||||
std::set<gd::String> results;
|
||||
|
||||
FindArgumentsInEventsAndDependencies(
|
||||
@@ -238,7 +238,7 @@ std::set<gd::String> EventsVariablesFinder::FindAllObjectVariables(
|
||||
project,
|
||||
layout,
|
||||
"objectvar",
|
||||
object.GetName());
|
||||
objectName);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
@@ -63,14 +63,14 @@ class EventsVariablesFinder {
|
||||
*
|
||||
* \param project The project
|
||||
* \param layout The layout to use.
|
||||
* \param object The object to be scanned
|
||||
* \param objectName The name of the object to be scanned
|
||||
* \return A std::set containing the names of all object variables used.
|
||||
*/
|
||||
static std::set<gd::String> FindAllObjectVariables(
|
||||
const gd::Platform& platform,
|
||||
const gd::Project& project,
|
||||
const gd::Layout& layout,
|
||||
const gd::Object& object);
|
||||
const gd::String& objectName);
|
||||
|
||||
private:
|
||||
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
||||
#define GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -20,7 +19,7 @@
|
||||
#include "GDCore/IDE/Events/ExpressionNodeLocationFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionTypeFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableOwnerFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariableParentFinder.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariablePathFinder.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
|
||||
@@ -147,6 +146,19 @@ struct GD_CORE_API ExpressionCompletionDescription {
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the scope of the variable, for a variable completion.
|
||||
*/
|
||||
gd::VariablesContainer::SourceType GetVariableScope() const {
|
||||
return variableScope;
|
||||
}
|
||||
|
||||
ExpressionCompletionDescription &
|
||||
SetVariableScope(gd::VariablesContainer::SourceType variableScope_) {
|
||||
variableScope = variableScope_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the prefix that must be completed.
|
||||
*/
|
||||
@@ -315,6 +327,7 @@ struct GD_CORE_API ExpressionCompletionDescription {
|
||||
size_t replacementEndPosition_)
|
||||
: completionKind(completionKind_),
|
||||
variableType(gd::Variable::Number),
|
||||
variableScope(gd::VariablesContainer::Unknown),
|
||||
replacementStartPosition(replacementStartPosition_),
|
||||
replacementEndPosition(replacementEndPosition_),
|
||||
isExact(false),
|
||||
@@ -325,6 +338,7 @@ struct GD_CORE_API ExpressionCompletionDescription {
|
||||
private:
|
||||
CompletionKind completionKind;
|
||||
gd::Variable::Type variableType;
|
||||
gd::VariablesContainer::SourceType variableScope;
|
||||
gd::String type;
|
||||
gd::String prefix;
|
||||
gd::String completion;
|
||||
@@ -525,7 +539,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
VariableAndItsParent variableAndItsParent =
|
||||
gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, node);
|
||||
|
||||
// If no child, we're at the end of a variable (like `GrandChild` in
|
||||
@@ -666,7 +680,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
VariableAndItsParent variableAndItsParent =
|
||||
gd::ExpressionVariableParentFinder::GetLastParentOfNode(
|
||||
gd::ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
platform, projectScopedContainers, node);
|
||||
|
||||
AddCompletionsForChildrenVariablesOf(
|
||||
@@ -933,6 +947,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
location.GetEndPosition());
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
description.SetVariableScope(variablesContainer.GetSourceType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
@@ -958,6 +973,7 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
location.GetEndPosition());
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
description.SetVariableScope(gd::VariablesContainer::Object);
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
@@ -1012,6 +1028,10 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
location.GetEndPosition());
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
description.SetVariableScope(
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetVariablesContainerFromVariableName(variableName)
|
||||
.GetSourceType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
@@ -1060,6 +1080,10 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
location.GetEndPosition());
|
||||
description.SetCompletion(variableName);
|
||||
description.SetVariableType(variable.GetType());
|
||||
description.SetVariableScope(
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetVariablesContainerFromVariableName(variableName)
|
||||
.GetSourceType());
|
||||
completions.push_back(description);
|
||||
|
||||
if (eagerlyCompleteIfExactMatch && variableName == search) {
|
||||
@@ -1113,5 +1137,3 @@ class GD_CORE_API ExpressionCompletionFinder
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONAUTOCOMPLETIONPROVIDER_H
|
||||
|
@@ -106,20 +106,20 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
auto variableExistence = objectsContainersList.HasObjectOrGroupWithVariableNamed(identifier.identifierName, identifier.childIdentifierName);
|
||||
|
||||
if (variableExistence == gd::ObjectsContainersList::DoesNotExist) {
|
||||
RaiseTypeError(_("This variable does not exist on this object or group."),
|
||||
identifier.childIdentifierNameLocation);
|
||||
RaiseUndeclaredVariableError(_("This variable does not exist on this object or group."),
|
||||
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
else if (variableExistence == gd::ObjectsContainersList::ExistsOnlyOnSomeObjectsOfTheGroup) {
|
||||
RaiseTypeError(_("This variable only exists on some objects of the group. It must be declared for all objects."),
|
||||
identifier.childIdentifierNameLocation);
|
||||
RaiseUndeclaredVariableError(_("This variable only exists on some objects of the group. It must be declared for all objects."),
|
||||
identifier.childIdentifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
else if (variableExistence == gd::ObjectsContainersList::GroupIsEmpty) {
|
||||
RaiseTypeError(_("This group is empty. Add an object to this group first."),
|
||||
identifier.identifierNameLocation);
|
||||
RaiseUndeclaredVariableError(_("This group is empty. Add an object to this group first."),
|
||||
identifier.identifierNameLocation, identifier.childIdentifierName, identifier.identifierName);
|
||||
|
||||
return true; // We should have found a variable.
|
||||
}
|
||||
@@ -166,8 +166,7 @@ bool ExpressionValidator::ValidateObjectVariableOrVariableOrProperty(
|
||||
return true; // We found a property, even if the child is not allowed.
|
||||
}
|
||||
|
||||
const gd::NamedPropertyDescriptor& property = projectScopedContainers
|
||||
.GetPropertiesContainersList().Get(identifier.identifierName).second;
|
||||
const gd::NamedPropertyDescriptor& property = propertiesContainersList.Get(identifier.identifierName).second;
|
||||
|
||||
if (property.GetType() == "Number") {
|
||||
childType = Type::Number;
|
||||
@@ -248,9 +247,10 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
|
||||
if (!function.behaviorName.empty() &&
|
||||
!objectsContainersList.HasBehaviorInObjectOrGroup(function.objectName,
|
||||
function.behaviorName)) {
|
||||
RaiseTypeError(_("This behavior is not attached to this object."),
|
||||
function.behaviorNameLocation,
|
||||
/*isFatal=*/false);
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::MissingBehavior,
|
||||
_("This behavior is not attached to this object."),
|
||||
function.behaviorNameLocation,
|
||||
/*isFatal=*/false, function.behaviorName, function.objectName);
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@@ -264,11 +264,11 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
|
||||
|
||||
if (gd::MetadataProvider::IsBadExpressionMetadata(metadata)) {
|
||||
if (function.functionName.empty()) {
|
||||
RaiseError("invalid_function_name",
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::InvalidFunctionName,
|
||||
_("Enter the name of the function to call."),
|
||||
function.location);
|
||||
} else {
|
||||
RaiseError("invalid_function_name",
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::InvalidFunctionName,
|
||||
_("Cannot find an expression with this name: ") +
|
||||
function.functionName + "\n" +
|
||||
_("Double check that you've not made any typo in the name."),
|
||||
@@ -341,13 +341,13 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
|
||||
|
||||
if (function.parameters.size() < minParametersCount) {
|
||||
RaiseError(
|
||||
"too_few_parameters",
|
||||
gd::ExpressionParserError::ErrorType::TooFewParameters,
|
||||
_("You have not entered enough parameters for the expression.") +
|
||||
" " + expectedCountMessage,
|
||||
function.location);
|
||||
} else {
|
||||
RaiseError(
|
||||
"extra_parameter",
|
||||
gd::ExpressionParserError::ErrorType::TooManyParameters,
|
||||
_("This parameter was not expected by this expression. Remove it "
|
||||
"or verify that you've entered the proper expression name.") +
|
||||
" " + expectedCountMessage,
|
||||
@@ -376,7 +376,10 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
|
||||
dynamic_cast<EmptyNode*>(parameter.get()) == nullptr) {
|
||||
auto currentParentType = parentType;
|
||||
parentType = StringToType(parameterMetadata.GetType());
|
||||
auto parentParameterExtraInfo = currentParameterExtraInfo;
|
||||
currentParameterExtraInfo = ¶meterMetadata.GetExtraInfo();
|
||||
parameter->Visit(*this);
|
||||
currentParameterExtraInfo = parentParameterExtraInfo;
|
||||
parentType = currentParentType;
|
||||
|
||||
const gd::String& expectedParameterType = parameterMetadata.GetType();
|
||||
@@ -384,7 +387,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
|
||||
ExpressionValidator::variableTypeString, expectedParameterType)) {
|
||||
if (dynamic_cast<IdentifierNode*>(parameter.get()) == nullptr &&
|
||||
dynamic_cast<VariableNode*>(parameter.get()) == nullptr) {
|
||||
RaiseError("malformed_variable_parameter",
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::MalformedVariableParameter,
|
||||
_("A variable name was expected but something else was "
|
||||
"written. Enter just the name of the variable for this "
|
||||
"parameter."),
|
||||
@@ -392,7 +395,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
|
||||
}
|
||||
} else if (gd::ParameterMetadata::IsObject(expectedParameterType)) {
|
||||
if (dynamic_cast<IdentifierNode*>(parameter.get()) == nullptr) {
|
||||
RaiseError("malformed_object_parameter",
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::MalformedObjectParameter,
|
||||
_("An object name was expected but something else was "
|
||||
"written. Enter just the name of the object for this "
|
||||
"parameter."),
|
||||
@@ -406,7 +409,7 @@ ExpressionValidator::Type ExpressionValidator::ValidateFunction(
|
||||
!gd::ParameterMetadata::IsExpression(
|
||||
ExpressionValidator::stringTypeString,
|
||||
expectedParameterType)) {
|
||||
RaiseError("unknown_parameter_type",
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::UnknownParameterType,
|
||||
_("This function is improperly set up. Reach out to the "
|
||||
"extension developer or a GDevelop maintainer to fix "
|
||||
"this issue"),
|
||||
@@ -440,6 +443,10 @@ const gd::String& ExpressionValidator::TypeToString(Type type) {
|
||||
return numberOrStringTypeString;
|
||||
case Type::Variable:
|
||||
return variableTypeString;
|
||||
case Type::LegacyVariable:
|
||||
// This function is only used to display error.
|
||||
// Users don't care if it's legacy or not.
|
||||
return variableTypeString;
|
||||
case Type::Object:
|
||||
return objectTypeString;
|
||||
case Type::Empty:
|
||||
@@ -466,7 +473,12 @@ ExpressionValidator::Type ExpressionValidator::StringToType(
|
||||
if (type == ExpressionValidator::variableTypeString ||
|
||||
gd::ParameterMetadata::IsExpression(
|
||||
ExpressionValidator::variableTypeString, type)) {
|
||||
return Type::Variable;
|
||||
if (gd::ValueTypeMetadata::IsTypeLegacyPreScopedVariable(type)) {
|
||||
return Type::LegacyVariable;
|
||||
}
|
||||
else {
|
||||
return Type::Variable;
|
||||
}
|
||||
}
|
||||
if (type == ExpressionValidator::objectTypeString ||
|
||||
gd::ParameterMetadata::IsObject(type)) {
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EXPRESSIONVALIDATOR_H
|
||||
#define GDCORE_EXPRESSIONVALIDATOR_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -39,12 +38,14 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
ExpressionValidator(const gd::Platform &platform_,
|
||||
const gd::ProjectScopedContainers & projectScopedContainers_,
|
||||
const gd::String &rootType_)
|
||||
const gd::String &rootType_,
|
||||
const gd::String &extraInfo_ = "")
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
parentType(StringToType(gd::ParameterMetadata::GetExpressionValueType(rootType_))),
|
||||
childType(Type::Unknown),
|
||||
forbidsUsageOfBracketsBecauseParentIsObject(false) {};
|
||||
forbidsUsageOfBracketsBecauseParentIsObject(false),
|
||||
currentParameterExtraInfo(&extraInfo_) {};
|
||||
virtual ~ExpressionValidator(){};
|
||||
|
||||
/**
|
||||
@@ -65,7 +66,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
*
|
||||
* Expressions with fatal error can't be generated.
|
||||
*/
|
||||
const std::vector<ExpressionParserDiagnostic*>& GetFatalErrors() {
|
||||
const std::vector<ExpressionParserError*>& GetFatalErrors() {
|
||||
return fatalErrors;
|
||||
};
|
||||
|
||||
@@ -74,7 +75,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
*
|
||||
* No errors means that the expression is valid.
|
||||
*/
|
||||
const std::vector<ExpressionParserDiagnostic*>& GetAllErrors() {
|
||||
const std::vector<ExpressionParserError*>& GetAllErrors() {
|
||||
return allErrors;
|
||||
};
|
||||
|
||||
@@ -93,14 +94,14 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
|
||||
if (leftType == Type::Number) {
|
||||
if (node.op == ' ') {
|
||||
RaiseError("syntax_error",
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::SyntaxError,
|
||||
"No operator found. Did you forget to enter an operator (like +, -, "
|
||||
"* or /) between numbers or expressions?", node.rightHandSide->location);
|
||||
}
|
||||
}
|
||||
else if (leftType == Type::String) {
|
||||
if (node.op == ' ') {
|
||||
RaiseError("syntax_error",
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::SyntaxError,
|
||||
"You must add the operator + between texts or expressions. For "
|
||||
"example: \"Your name: \" + VariableString(PlayerName).", node.rightHandSide->location);
|
||||
}
|
||||
@@ -115,7 +116,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
_("Operators (+, -, /, *) can't be used with an object name. Remove "
|
||||
"the operator."),
|
||||
node.rightHandSide->location);
|
||||
} else if (leftType == Type::Variable) {
|
||||
} else if (leftType == Type::Variable || leftType == Type::LegacyVariable) {
|
||||
RaiseOperatorError(
|
||||
_("Operators (+, -, /, *) can't be used in variable names. Remove "
|
||||
"the operator from the variable name."),
|
||||
@@ -162,7 +163,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
_("Operators (+, -) can't be used with an object name. Remove the "
|
||||
"operator."),
|
||||
node.location);
|
||||
} else if (rightType == Type::Variable) {
|
||||
} else if (rightType == Type::Variable || rightType == Type::LegacyVariable) {
|
||||
RaiseTypeError(
|
||||
_("Operators (+, -) can't be used in variable names. Remove "
|
||||
"the operator from the variable name."),
|
||||
@@ -200,7 +201,14 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
ReportAnyError(node);
|
||||
|
||||
if (parentType == Type::Variable) {
|
||||
childType = Type::Variable;
|
||||
childType = parentType;
|
||||
|
||||
CheckVariableExistence(node.location, node.name);
|
||||
if (node.child) {
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
} else if (parentType == Type::LegacyVariable) {
|
||||
childType = parentType;
|
||||
|
||||
if (node.child) {
|
||||
node.child->Visit(*this);
|
||||
@@ -270,7 +278,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
ReportAnyError(node);
|
||||
|
||||
if (forbidsUsageOfBracketsBecauseParentIsObject) {
|
||||
RaiseError("brackets_not_allowed_for_objects",
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::BracketsNotAllowedForObjects,
|
||||
_("You can't use the brackets to access an object variable. "
|
||||
"Use a dot followed by the variable name, like this: "
|
||||
"`MyObject.MyVariable`."),
|
||||
@@ -279,9 +287,14 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
forbidsUsageOfBracketsBecauseParentIsObject = false;
|
||||
|
||||
Type currentParentType = parentType;
|
||||
Type currentChildType = childType;
|
||||
parentType = Type::NumberOrString;
|
||||
auto parentParameterExtraInfo = currentParameterExtraInfo;
|
||||
currentParameterExtraInfo = nullptr;
|
||||
node.expression->Visit(*this);
|
||||
currentParameterExtraInfo = parentParameterExtraInfo;
|
||||
parentType = currentParentType;
|
||||
childType = currentChildType;
|
||||
|
||||
if (node.child) {
|
||||
node.child->Visit(*this);
|
||||
@@ -293,7 +306,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
|
||||
// The identifier is not a variable, so either the variable is not properly declared
|
||||
// or it's a text without quotes.
|
||||
RaiseTypeError(_("You must wrap your text inside double quotes "
|
||||
RaiseUnknownIdentifierError(_("You must wrap your text inside double quotes "
|
||||
"(example: \"Hello world\")."),
|
||||
node.location);
|
||||
}
|
||||
@@ -301,20 +314,22 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
else if (parentType == Type::Number) {
|
||||
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
|
||||
// The identifier is not a variable, so the variable is not properly declared.
|
||||
RaiseTypeError(
|
||||
_("You must enter a number."), node.location);
|
||||
RaiseUnknownIdentifierError(_("You must enter a number."), node.location);
|
||||
}
|
||||
}
|
||||
else if (parentType == Type::NumberOrString) {
|
||||
if (!ValidateObjectVariableOrVariableOrProperty(node)) {
|
||||
// The identifier is not a variable, so either the variable is not properly declared
|
||||
// or it's a text without quotes.
|
||||
RaiseTypeError(
|
||||
RaiseUnknownIdentifierError(
|
||||
_("You must enter a number or a text, wrapped inside double quotes (example: \"Hello world\"), or a variable name."),
|
||||
node.location);
|
||||
}
|
||||
}
|
||||
else if (parentType != Type::Object && parentType != Type::Variable) {
|
||||
else if (parentType == Type::Variable) {
|
||||
CheckVariableExistence(node.location, node.identifierName);
|
||||
}
|
||||
else if (parentType != Type::Object && parentType != Type::LegacyVariable) {
|
||||
// It can't happen.
|
||||
RaiseTypeError(
|
||||
_("You've entered a name, but this type was expected:") + " " + TypeToString(parentType),
|
||||
@@ -338,7 +353,7 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
} else if (parentType == Type::String) {
|
||||
message = _(
|
||||
"You must enter a text (between quotes) or a valid expression call.");
|
||||
} else if (parentType == Type::Variable) {
|
||||
} else if (parentType == Type::Variable || parentType == Type::LegacyVariable) {
|
||||
message = _("You must enter a variable name.");
|
||||
} else if (parentType == Type::Object) {
|
||||
message = _("You must enter a valid object name.");
|
||||
@@ -351,12 +366,51 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
}
|
||||
|
||||
private:
|
||||
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, Object, Empty};
|
||||
enum Type {Unknown = 0, Number, String, NumberOrString, Variable, LegacyVariable, Object, Empty};
|
||||
Type ValidateFunction(const gd::FunctionCallNode& function);
|
||||
bool ValidateObjectVariableOrVariableOrProperty(const gd::IdentifierNode& identifier);
|
||||
|
||||
void CheckVariableExistence(const ExpressionParserLocation &location, const gd::String& name) {
|
||||
if (!currentParameterExtraInfo || *currentParameterExtraInfo != "AllowUndeclaredVariable") {
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
name,
|
||||
[&]() {
|
||||
// This represents an object.
|
||||
RaiseVariableNameCollisionError(
|
||||
_("This variable has the same name as an object. Consider "
|
||||
"renaming one or the other."),
|
||||
location, name);
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
},
|
||||
[&]() {
|
||||
// This is a property.
|
||||
// This error won't happen unless the priority is changed.
|
||||
RaiseVariableNameCollisionError(
|
||||
_("This variable has the same name as a property. Consider "
|
||||
"renaming one or the other."),
|
||||
location, name);
|
||||
},
|
||||
[&]() {
|
||||
// This is a parameter.
|
||||
// This error won't happen unless the priority is changed.
|
||||
RaiseVariableNameCollisionError(
|
||||
_("This variable has the same name as a parameter. Consider "
|
||||
"renaming one or the other."),
|
||||
location, name);
|
||||
},
|
||||
[&]() {
|
||||
// This is something else.
|
||||
RaiseUndeclaredVariableError(
|
||||
_("No variable with this name found."), location,
|
||||
name);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ReportAnyError(const ExpressionNode& node, bool isFatal = true) {
|
||||
if (node.diagnostic && node.diagnostic->IsError()) {
|
||||
if (node.diagnostic) {
|
||||
// Syntax errors are holden by the AST nodes.
|
||||
// It's fine to give pointers on them as the AST live longer than errors
|
||||
// handling.
|
||||
@@ -367,10 +421,13 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
}
|
||||
}
|
||||
|
||||
void RaiseError(const gd::String &type,
|
||||
const gd::String &message, const ExpressionParserLocation &location, bool isFatal = true) {
|
||||
void RaiseError(gd::ExpressionParserError::ErrorType type,
|
||||
const gd::String &message,
|
||||
const ExpressionParserLocation &location, bool isFatal = true,
|
||||
const gd::String &actualValue = "",
|
||||
const gd::String &objectName = "") {
|
||||
auto diagnostic = gd::make_unique<ExpressionParserError>(
|
||||
type, message, location);
|
||||
type, message, location, actualValue, objectName);
|
||||
allErrors.push_back(diagnostic.get());
|
||||
if (isFatal) {
|
||||
fatalErrors.push_back(diagnostic.get());
|
||||
@@ -381,14 +438,39 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
supplementalErrors.push_back(std::move(diagnostic));
|
||||
}
|
||||
|
||||
void RaiseTypeError(
|
||||
const gd::String &message, const ExpressionParserLocation &location, bool isFatal = true) {
|
||||
RaiseError("type_error", message, location, isFatal);
|
||||
void RaiseUnknownIdentifierError(const gd::String &message,
|
||||
const ExpressionParserLocation &location) {
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::UnknownIdentifier, message,
|
||||
location);
|
||||
}
|
||||
|
||||
void RaiseOperatorError(
|
||||
const gd::String &message, const ExpressionParserLocation &location) {
|
||||
RaiseError("invalid_operator", message, location);
|
||||
void RaiseUndeclaredVariableError(const gd::String &message,
|
||||
const ExpressionParserLocation &location,
|
||||
const gd::String &variableName,
|
||||
const gd::String &objectName = "") {
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::UndeclaredVariable,
|
||||
message, location, true, variableName, objectName);
|
||||
}
|
||||
|
||||
void RaiseVariableNameCollisionError(const gd::String &message,
|
||||
const ExpressionParserLocation &location,
|
||||
const gd::String &variableName,
|
||||
const gd::String &objectName = "") {
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::VariableNameCollision,
|
||||
message, location, false, variableName, objectName);
|
||||
}
|
||||
|
||||
void RaiseTypeError(const gd::String &message,
|
||||
const ExpressionParserLocation &location,
|
||||
bool isFatal = true) {
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::MismatchedType, message,
|
||||
location, isFatal);
|
||||
}
|
||||
|
||||
void RaiseOperatorError(const gd::String &message,
|
||||
const ExpressionParserLocation &location) {
|
||||
RaiseError(gd::ExpressionParserError::ErrorType::InvalidOperator, message,
|
||||
location);
|
||||
}
|
||||
|
||||
void ReadChildTypeFromVariable(gd::Variable::Type variableType) {
|
||||
@@ -412,20 +494,21 @@ class GD_CORE_API ExpressionValidator : public ExpressionParser2NodeWorker {
|
||||
static const gd::String stringTypeString;
|
||||
static const gd::String numberOrStringTypeString;
|
||||
static const gd::String variableTypeString;
|
||||
static const gd::String legacyVariableTypeString;
|
||||
static const gd::String objectTypeString;
|
||||
static const gd::String identifierTypeString;
|
||||
static const gd::String emptyTypeString;
|
||||
|
||||
std::vector<ExpressionParserDiagnostic*> fatalErrors;
|
||||
std::vector<ExpressionParserDiagnostic*> allErrors;
|
||||
std::vector<std::unique_ptr<ExpressionParserDiagnostic>> supplementalErrors;
|
||||
std::vector<ExpressionParserError*> fatalErrors;
|
||||
std::vector<ExpressionParserError*> allErrors;
|
||||
std::vector<std::unique_ptr<ExpressionParserError>> supplementalErrors;
|
||||
Type childType; ///< The type "discovered" down the tree and passed up.
|
||||
Type parentType; ///< The type "required" by the top of the tree.
|
||||
bool forbidsUsageOfBracketsBecauseParentIsObject;
|
||||
const gd::String *currentParameterExtraInfo;
|
||||
const gd::Platform &platform;
|
||||
const gd::ProjectScopedContainers &projectScopedContainers;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXPRESSIONVALIDATOR_H
|
||||
|
55
Core/GDCore/IDE/Events/ExpressionVariableNameFinder.h
Normal file
55
Core/GDCore/IDE/Events/ExpressionVariableNameFinder.h
Normal file
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Find the variable name from a variable expression.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariableNameFinder : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
static const gd::String GetVariableName(gd::ExpressionNode& node) {
|
||||
gd::ExpressionVariableNameFinder typeFinder;
|
||||
node.Visit(typeFinder);
|
||||
return typeFinder.variableName;
|
||||
}
|
||||
|
||||
virtual ~ExpressionVariableNameFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionVariableNameFinder()
|
||||
: variableName("") {};
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
variableName = node.name;
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
variableName = node.identifierName;
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {}
|
||||
|
||||
private:
|
||||
gd::String variableName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -1,374 +0,0 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Extensions/Metadata/ExpressionMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/ObjectMetadata.h"
|
||||
#include "GDCore/Extensions/Metadata/ParameterMetadata.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
|
||||
namespace gd {
|
||||
class Expression;
|
||||
class ObjectsContainer;
|
||||
class Platform;
|
||||
class ParameterMetadata;
|
||||
class ExpressionMetadata;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Contains a variables container or a variable. Useful
|
||||
* to refer to the parent of a variable (which can be a VariablesContainer
|
||||
* or another Variable).
|
||||
*/
|
||||
struct VariableAndItsParent {
|
||||
const gd::VariablesContainer* parentVariablesContainer;
|
||||
const gd::Variable* parentVariable;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Find the last parent (i.e: the variables container) of a node
|
||||
* representing a variable.
|
||||
*
|
||||
* Useful for completions, to know which variables can be entered in a node.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariableParentFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
static VariableAndItsParent GetLastParentOfNode(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node) {
|
||||
gd::ExpressionVariableParentFinder typeFinder(platform,
|
||||
projectScopedContainers);
|
||||
node.Visit(typeFinder);
|
||||
return typeFinder.variableAndItsParent;
|
||||
}
|
||||
|
||||
virtual ~ExpressionVariableParentFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionVariableParentFinder(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_)
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
variableNode(nullptr),
|
||||
thisIsALegacyPrescopedVariable(false),
|
||||
bailOutBecauseEmptyVariableName(false),
|
||||
legacyPrescopedVariablesContainer(nullptr),
|
||||
variableAndItsParent{} {};
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (variableNode != nullptr) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
|
||||
if (thisIsALegacyPrescopedVariable) {
|
||||
// The node represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
childVariableNames.insert(childVariableNames.begin(), node.name);
|
||||
if (legacyPrescopedVariablesContainer)
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
*legacyPrescopedVariablesContainer, childVariableNames);
|
||||
} else {
|
||||
// Otherwise, the identifier is to be interpreted as usual:
|
||||
// it can be an object (on which a variable is accessed),
|
||||
// or a variable.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
node.name,
|
||||
[&]() {
|
||||
// This is an object.
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(node.name);
|
||||
if (variablesContainer)
|
||||
variableAndItsParent =
|
||||
WalkUntilLastParent(*variablesContainer, childVariableNames);
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList().Has(
|
||||
node.name)) {
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
projectScopedContainers.GetVariablesContainersList().Get(
|
||||
node.name),
|
||||
childVariableNames);
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// Ignore properties here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore parameters here.
|
||||
// There is no support for "children" of parameters.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore unrecognised identifiers here.
|
||||
});
|
||||
}
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.name.empty() && node.child) {
|
||||
// A variable accessor should always have a name if it has a child (i.e:
|
||||
// another accessor). While the parser may have generated an empty name,
|
||||
// flag this so we avoid finding a wrong parent (and so, run the risk of
|
||||
// giving wrong autocompletions).
|
||||
bailOutBecauseEmptyVariableName = true;
|
||||
}
|
||||
childVariableNames.insert(childVariableNames.begin(), node.name);
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (variableNode != nullptr) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
// This node is not necessarily a variable node.
|
||||
// It will be checked when visiting the FunctionCallNode, just after.
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
|
||||
if (thisIsALegacyPrescopedVariable) {
|
||||
// The identifier represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
if (!node.childIdentifierName.empty())
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.childIdentifierName);
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.identifierName);
|
||||
|
||||
if (legacyPrescopedVariablesContainer)
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
*legacyPrescopedVariablesContainer, childVariableNames);
|
||||
|
||||
} else {
|
||||
// Otherwise, the identifier is to be interpreted as usual:
|
||||
// it can be an object (on which a variable is accessed),
|
||||
// or a variable.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
node.identifierName,
|
||||
[&]() {
|
||||
// This is an object.
|
||||
if (!node.childIdentifierName.empty())
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.childIdentifierName);
|
||||
|
||||
const auto* variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(node.identifierName);
|
||||
if (variablesContainer)
|
||||
variableAndItsParent =
|
||||
WalkUntilLastParent(*variablesContainer, childVariableNames);
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (!node.childIdentifierName.empty())
|
||||
childVariableNames.insert(childVariableNames.begin(),
|
||||
node.childIdentifierName);
|
||||
|
||||
if (projectScopedContainers.GetVariablesContainersList().Has(
|
||||
node.identifierName)) {
|
||||
variableAndItsParent = WalkUntilLastParent(
|
||||
projectScopedContainers.GetVariablesContainersList().Get(
|
||||
node.identifierName),
|
||||
childVariableNames);
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// Ignore properties here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore parameters here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore unrecognised identifiers here.
|
||||
});
|
||||
}
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
// Add a child with an empty name, which will be interpreted as
|
||||
// "take the first child/item of the structure/array".
|
||||
childVariableNames.insert(childVariableNames.begin(), "");
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {
|
||||
if (variableNode == nullptr) {
|
||||
return;
|
||||
}
|
||||
int parameterIndex = -1;
|
||||
for (int i = 0; i < functionCall.parameters.size(); i++) {
|
||||
if (functionCall.parameters.at(i).get() == variableNode) {
|
||||
parameterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameterIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
|
||||
const gd::ParameterMetadata* parameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, parameterIndex);
|
||||
if (parameterMetadata == nullptr) return; // Unexpected
|
||||
|
||||
// Support for legacy pre-scoped variables:
|
||||
if (parameterMetadata->GetValueTypeMetadata().IsLegacyPreScopedVariable()) {
|
||||
if (parameterMetadata->GetType() == "objectvar") {
|
||||
// Legacy convention where a "objectvar"
|
||||
// parameter represents a variable of the object represented by the
|
||||
// previous "object" parameter. The object on which the function is
|
||||
// called is returned if no previous parameters are objects.
|
||||
gd::String objectName = functionCall.objectName;
|
||||
for (int previousIndex = parameterIndex - 1; previousIndex >= 0;
|
||||
previousIndex--) {
|
||||
const gd::ParameterMetadata* previousParameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, previousIndex);
|
||||
if (previousParameterMetadata != nullptr &&
|
||||
gd::ParameterMetadata::IsObject(
|
||||
previousParameterMetadata->GetType())) {
|
||||
auto previousParameterNode =
|
||||
functionCall.parameters[previousIndex].get();
|
||||
IdentifierNode* objectNode =
|
||||
dynamic_cast<IdentifierNode*>(previousParameterNode);
|
||||
objectName = objectNode->identifierName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
legacyPrescopedVariablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
thisIsALegacyPrescopedVariable = true;
|
||||
} else if (parameterMetadata->GetType() == "scenevar") {
|
||||
legacyPrescopedVariablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
thisIsALegacyPrescopedVariable = true;
|
||||
} else if (parameterMetadata->GetType() == "globalvar") {
|
||||
legacyPrescopedVariablesContainer =
|
||||
projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer();
|
||||
thisIsALegacyPrescopedVariable = true;
|
||||
}
|
||||
} else {
|
||||
thisIsALegacyPrescopedVariable = false;
|
||||
legacyPrescopedVariablesContainer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::Variable& variable,
|
||||
const std::vector<gd::String>& childVariableNames,
|
||||
size_t startIndex = 0) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
const gd::Variable* currentVariable = &variable;
|
||||
|
||||
// Walk until size - 1 as we want the last parent.
|
||||
for (size_t index = startIndex; index + 1 < childVariableNames.size();
|
||||
++index) {
|
||||
const gd::String& childName = childVariableNames[index];
|
||||
|
||||
if (childName.empty()) {
|
||||
if (currentVariable->GetChildrenCount() == 0) {
|
||||
// The array or structure is empty, we can't walk through it - there
|
||||
// is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
if (currentVariable->GetType() == gd::Variable::Array) {
|
||||
currentVariable = ¤tVariable->GetAtIndex(0);
|
||||
} else {
|
||||
currentVariable =
|
||||
currentVariable->GetAllChildren().begin()->second.get();
|
||||
}
|
||||
} else {
|
||||
if (!currentVariable->HasChild(childName)) {
|
||||
// Non existing child - there is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
currentVariable = ¤tVariable->GetChild(childName);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the last parent of the chain of variables (so not the last
|
||||
// variable but the one before it).
|
||||
return {.parentVariable = currentVariable};
|
||||
}
|
||||
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::VariablesContainer& variablesContainer,
|
||||
const std::vector<gd::String>& childVariableNames) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
if (childVariableNames.empty())
|
||||
return {}; // There is no "parent" to the variables container itself.
|
||||
|
||||
const gd::String& firstChildName = *childVariableNames.begin();
|
||||
|
||||
const gd::Variable* variable = variablesContainer.Has(firstChildName)
|
||||
? &variablesContainer.Get(firstChildName)
|
||||
: nullptr;
|
||||
if (childVariableNames.size() == 1 || !variable)
|
||||
return {// Only one child: the parent is the variables container itself.
|
||||
.parentVariablesContainer = &variablesContainer};
|
||||
|
||||
return WalkUntilLastParent(*variable, childVariableNames, 1);
|
||||
}
|
||||
|
||||
gd::ExpressionNode* variableNode;
|
||||
std::vector<gd::String> childVariableNames;
|
||||
bool thisIsALegacyPrescopedVariable;
|
||||
bool bailOutBecauseEmptyVariableName;
|
||||
const gd::VariablesContainer* legacyPrescopedVariablesContainer;
|
||||
VariableAndItsParent variableAndItsParent;
|
||||
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
};
|
||||
|
||||
} // namespace gd
|
195
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.cpp
Normal file
195
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.cpp
Normal file
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "ExpressionVariablePathFinder.h"
|
||||
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Find the pre-scoped container of legacy variables or the object name
|
||||
* from the function call node.
|
||||
*/
|
||||
class GD_CORE_API ExpressionLiteralFinder : public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
virtual ~ExpressionLiteralFinder(){};
|
||||
|
||||
gd::String literalValue;
|
||||
|
||||
ExpressionLiteralFinder() : literalValue(""){};
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode &node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode &node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode &node) override {}
|
||||
void OnVisitNumberNode(NumberNode &node) override {
|
||||
literalValue = node.number;
|
||||
}
|
||||
void OnVisitTextNode(TextNode &node) override { literalValue = node.text; }
|
||||
void OnVisitVariableNode(VariableNode &node) override {}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode &node) override {}
|
||||
void OnVisitIdentifierNode(IdentifierNode &node) override {}
|
||||
void OnVisitEmptyNode(EmptyNode &node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode &node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode &node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode &functionCall) override {}
|
||||
};
|
||||
|
||||
void ExpressionVariablePathFinder::OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode &node) {
|
||||
// Try to find a literal accessor or add a child with an empty name, which
|
||||
// will be interpreted as "take the first child/item of the structure/array".
|
||||
gd::ExpressionLiteralFinder expressionLiteralFinder;
|
||||
if (node.expression) {
|
||||
node.expression->Visit(expressionLiteralFinder);
|
||||
}
|
||||
childVariableNames.push_back(expressionLiteralFinder.literalValue);
|
||||
|
||||
if (node.child && &node != lastNodeToCheck) {
|
||||
node.child->Visit(*this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Find the pre-scoped container of legacy variables or the object name
|
||||
* from the function call node.
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariableContextFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
virtual ~ExpressionVariableContextFinder(){};
|
||||
|
||||
gd::String objectName;
|
||||
gd::String parameterType;
|
||||
gd::ExpressionNode* variableNode;
|
||||
|
||||
ExpressionVariableContextFinder(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_)
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
variableNode(nullptr),
|
||||
objectName(""),
|
||||
parameterType("") {};
|
||||
|
||||
protected:
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
if (variableNode) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
if (variableNode) {
|
||||
// This is not possible
|
||||
return;
|
||||
}
|
||||
// This node is not necessarily a variable node.
|
||||
// It will be checked when visiting the FunctionCallNode, just after.
|
||||
variableNode = &node;
|
||||
|
||||
// Check if the parent is a function call, in which we might be dealing
|
||||
// with a legacy pre-scoped variable parameter:
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override {
|
||||
if (node.parent) node.parent->Visit(*this);
|
||||
}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {
|
||||
int parameterIndex = -1;
|
||||
for (int i = 0; i < functionCall.parameters.size(); i++) {
|
||||
if (functionCall.parameters.at(i).get() == variableNode) {
|
||||
parameterIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameterIndex < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& objectsContainersList =
|
||||
projectScopedContainers.GetObjectsContainersList();
|
||||
|
||||
const gd::ParameterMetadata* parameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, parameterIndex);
|
||||
if (parameterMetadata == nullptr) return; // Unexpected
|
||||
|
||||
if (parameterMetadata->GetType() == "objectvar") {
|
||||
// Legacy convention where a "objectvar"
|
||||
// parameter represents a variable of the object represented by the
|
||||
// previous "object" parameter. The object on which the function is
|
||||
// called is returned if no previous parameters are objects.
|
||||
objectName = functionCall.objectName;
|
||||
for (int previousIndex = parameterIndex - 1; previousIndex >= 0;
|
||||
previousIndex--) {
|
||||
const gd::ParameterMetadata* previousParameterMetadata =
|
||||
MetadataProvider::GetFunctionCallParameterMetadata(
|
||||
platform, objectsContainersList, functionCall, previousIndex);
|
||||
if (previousParameterMetadata != nullptr &&
|
||||
gd::ParameterMetadata::IsObject(
|
||||
previousParameterMetadata->GetType())) {
|
||||
auto previousParameterNode =
|
||||
functionCall.parameters[previousIndex].get();
|
||||
IdentifierNode* objectNode =
|
||||
dynamic_cast<IdentifierNode*>(previousParameterNode);
|
||||
objectName = objectNode->identifierName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
parameterType = parameterMetadata->GetType();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
|
||||
};
|
||||
|
||||
VariableAndItsParent ExpressionVariablePathFinder::GetLastParentOfNode(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::ExpressionNode &node) {
|
||||
|
||||
gd::ExpressionVariableContextFinder contextFinder(platform,
|
||||
projectScopedContainers);
|
||||
node.Visit(contextFinder);
|
||||
if (!contextFinder.variableNode) {
|
||||
return {};
|
||||
}
|
||||
|
||||
gd::ExpressionVariablePathFinder typeFinder(platform, projectScopedContainers,
|
||||
contextFinder.parameterType,
|
||||
contextFinder.objectName, &node);
|
||||
contextFinder.variableNode->Visit(typeFinder);
|
||||
|
||||
if (typeFinder.variableName.empty() || !typeFinder.variablesContainer) {
|
||||
return {};
|
||||
}
|
||||
return typeFinder.WalkUntilLastParent(*typeFinder.variablesContainer,
|
||||
typeFinder.childVariableNames);
|
||||
}
|
||||
|
||||
} // namespace gd
|
357
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.h
Normal file
357
Core/GDCore/IDE/Events/ExpressionVariablePathFinder.h
Normal file
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2Node.h"
|
||||
#include "GDCore/Events/Parsers/ExpressionParser2NodeWorker.h"
|
||||
#include "GDCore/Project/ProjectScopedContainers.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
|
||||
namespace gd {
|
||||
class Platform;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Contains a variables container or a variable. Useful
|
||||
* to refer to the parent of a variable (which can be a VariablesContainer
|
||||
* or another Variable).
|
||||
*/
|
||||
struct VariableAndItsParent {
|
||||
const gd::VariablesContainer* parentVariablesContainer;
|
||||
const gd::Variable* parentVariable;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Find a variable path from an expression node.
|
||||
*
|
||||
* \see gd::ExpressionParser2
|
||||
*/
|
||||
class GD_CORE_API ExpressionVariablePathFinder
|
||||
: public ExpressionParser2NodeWorker {
|
||||
public:
|
||||
|
||||
static VariableAndItsParent GetLastParentOfNode(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node);
|
||||
|
||||
static const gd::Variable::Type GetVariableType(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node, const gd::String& objectName) {
|
||||
// The context is not checked because this is called on variable parameters.
|
||||
gd::String parameterType = objectName.empty() ? "variable" : "objectvar";
|
||||
gd::String objName = objectName;
|
||||
gd::ExpressionVariablePathFinder typeFinder(
|
||||
platform, projectScopedContainers, parameterType, objName);
|
||||
node.Visit(typeFinder);
|
||||
|
||||
if (typeFinder.variableName.empty() || !typeFinder.variablesContainer) {
|
||||
return gd::Variable::Unknown;
|
||||
}
|
||||
auto *variable = typeFinder.WalkUntilLastChild(
|
||||
typeFinder.variablesContainer->Get(typeFinder.variableName),
|
||||
typeFinder.childVariableNames);
|
||||
return variable ? variable->GetType() : gd::Variable::Unknown;
|
||||
}
|
||||
|
||||
static const gd::Variable::Type GetArrayVariableType(
|
||||
const gd::Platform& platform,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers,
|
||||
gd::ExpressionNode& node, const gd::String& objectName) {
|
||||
// The context is not checked because this is called on variable parameters.
|
||||
gd::String parameterType = objectName.empty() ? "variable" : "objectvar";
|
||||
gd::String objName = objectName;
|
||||
gd::ExpressionVariablePathFinder typeFinder(
|
||||
platform, projectScopedContainers, parameterType, objName);
|
||||
node.Visit(typeFinder);
|
||||
|
||||
if (typeFinder.variableName.empty() || !typeFinder.variablesContainer) {
|
||||
return gd::Variable::Unknown;
|
||||
}
|
||||
auto *variable = typeFinder.WalkUntilLastChild(
|
||||
typeFinder.variablesContainer->Get(typeFinder.variableName),
|
||||
typeFinder.childVariableNames);
|
||||
if (variable && variable->GetType() != gd::Variable::Array) {
|
||||
return gd::Variable::Unknown;
|
||||
}
|
||||
return variable && variable->GetChildrenCount() > 0
|
||||
? variable->GetAtIndex(0).GetType()
|
||||
: gd::Variable::Unknown;
|
||||
}
|
||||
|
||||
virtual ~ExpressionVariablePathFinder(){};
|
||||
|
||||
protected:
|
||||
ExpressionVariablePathFinder(
|
||||
const gd::Platform& platform_,
|
||||
const gd::ProjectScopedContainers& projectScopedContainers_,
|
||||
const gd::String& parameterType_,
|
||||
gd::String& objectName_,
|
||||
const gd::ExpressionNode* lastNodeToCheck_ = nullptr)
|
||||
: platform(platform_),
|
||||
projectScopedContainers(projectScopedContainers_),
|
||||
parameterType(parameterType_),
|
||||
objectName(objectName_),
|
||||
lastNodeToCheck(lastNodeToCheck_),
|
||||
variablesContainer(nullptr),
|
||||
variableName(""),
|
||||
bailOutBecauseEmptyVariableName(false) {};
|
||||
|
||||
void OnVisitVariableBracketAccessorNode(
|
||||
VariableBracketAccessorNode& node) override;
|
||||
|
||||
void OnVisitSubExpressionNode(SubExpressionNode& node) override {}
|
||||
void OnVisitOperatorNode(OperatorNode& node) override {}
|
||||
void OnVisitUnaryOperatorNode(UnaryOperatorNode& node) override {}
|
||||
void OnVisitNumberNode(NumberNode& node) override {}
|
||||
void OnVisitTextNode(TextNode& node) override {}
|
||||
void OnVisitVariableNode(VariableNode& node) override {
|
||||
FindVariableFor(node.name);
|
||||
if (node.child && &node != lastNodeToCheck) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitVariableAccessorNode(VariableAccessorNode& node) override {
|
||||
if (node.name.empty() && node.child) {
|
||||
// A variable accessor should always have a name if it has a child (i.e:
|
||||
// another accessor). While the parser may have generated an empty name,
|
||||
// flag this so we avoid finding a wrong parent (and so, run the risk of
|
||||
// giving wrong autocompletions).
|
||||
bailOutBecauseEmptyVariableName = true;
|
||||
}
|
||||
if (variableName.empty()) {
|
||||
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(objectName,
|
||||
node.name) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variableName = node.name;
|
||||
variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
}
|
||||
} else {
|
||||
childVariableNames.push_back(node.name);
|
||||
}
|
||||
if (node.child && &node != lastNodeToCheck) node.child->Visit(*this);
|
||||
}
|
||||
void OnVisitIdentifierNode(IdentifierNode& node) override {
|
||||
FindVariableFor(node.identifierName, node.identifierNameDotLocation.IsValid() ? &node.childIdentifierName : nullptr);
|
||||
}
|
||||
void OnVisitEmptyNode(EmptyNode& node) override {}
|
||||
void OnVisitObjectFunctionNameNode(ObjectFunctionNameNode& node) override {}
|
||||
void OnVisitFunctionCallNode(FunctionCallNode& functionCall) override {}
|
||||
|
||||
void FindVariableFor(const gd::String& identifier, gd::String* childIdentifier = nullptr) {
|
||||
if (!objectName.empty()) {
|
||||
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(objectName,
|
||||
identifier) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variableName = identifier;
|
||||
variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (parameterType == "scenevar") {
|
||||
// The node represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
variablesContainer = projectScopedContainers.GetVariablesContainersList()
|
||||
.GetBottomMostVariablesContainer();
|
||||
variableName = identifier;
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
}
|
||||
else if (parameterType == "globalvar") {
|
||||
// The node represents a variable name, and the variables container
|
||||
// containing it was identified in the FunctionCallNode.
|
||||
variablesContainer = projectScopedContainers.GetVariablesContainersList()
|
||||
.GetTopMostVariablesContainer();
|
||||
variableName = identifier;
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, the identifier is to be interpreted as usual:
|
||||
// it can be an object (on which a variable is accessed),
|
||||
// or a variable.
|
||||
projectScopedContainers.MatchIdentifierWithName<void>(
|
||||
identifier,
|
||||
[&]() {
|
||||
objectName = identifier;
|
||||
if (childIdentifier) {
|
||||
if (parameterType == "variable") {
|
||||
// An object is overlapping the variable.
|
||||
// Even in "variable" parameters, this is not allowed to be
|
||||
// consistent with expressions.
|
||||
} else {
|
||||
// It's an object variable expression.
|
||||
const auto& objectsContainersList = projectScopedContainers.GetObjectsContainersList();
|
||||
if (objectsContainersList.HasObjectOrGroupWithVariableNamed(objectName,
|
||||
*childIdentifier) !=
|
||||
gd::ObjectsContainersList::VariableExistence::DoesNotExist) {
|
||||
variableName = *childIdentifier;
|
||||
variablesContainer =
|
||||
projectScopedContainers.GetObjectsContainersList()
|
||||
.GetObjectOrGroupVariablesContainer(objectName);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// This is a variable.
|
||||
if (projectScopedContainers.GetVariablesContainersList().Has(identifier)) {
|
||||
variablesContainer =
|
||||
&(projectScopedContainers.GetVariablesContainersList()
|
||||
.GetVariablesContainerFromVariableName(identifier));
|
||||
variableName = identifier;
|
||||
if (childIdentifier) {
|
||||
childVariableNames.push_back(*childIdentifier);
|
||||
}
|
||||
}
|
||||
},
|
||||
[&]() {
|
||||
// Ignore properties here.
|
||||
// There is no support for "children" of properties.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore parameters here.
|
||||
// There is no support for "children" of parameters.
|
||||
},
|
||||
[&]() {
|
||||
// Ignore unrecognised identifiers here.
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const gd::Variable* WalkUntilLastChild(
|
||||
const gd::Variable& variable,
|
||||
const std::vector<gd::String>& childVariableNames,
|
||||
size_t startIndex = 0) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return nullptr; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
const gd::Variable* currentVariable = &variable;
|
||||
|
||||
for (size_t index = startIndex; index < childVariableNames.size();
|
||||
++index) {
|
||||
const gd::String& childName = childVariableNames[index];
|
||||
|
||||
if (childName.empty()) {
|
||||
if (currentVariable->GetChildrenCount() == 0) {
|
||||
// The array or structure is empty, we can't walk through it - there
|
||||
// is no "parent".
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (currentVariable->GetType() == gd::Variable::Array) {
|
||||
currentVariable = ¤tVariable->GetAtIndex(0);
|
||||
} else {
|
||||
currentVariable =
|
||||
currentVariable->GetAllChildren().begin()->second.get();
|
||||
}
|
||||
} else {
|
||||
if (!currentVariable->HasChild(childName)) {
|
||||
// Non existing child - there is no "parent".
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
currentVariable = ¤tVariable->GetChild(childName);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the last parent of the chain of variables (so not the last
|
||||
// variable but the one before it).
|
||||
return currentVariable;
|
||||
}
|
||||
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::Variable& variable,
|
||||
const std::vector<gd::String>& childVariableNames,
|
||||
size_t startIndex = 0) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
const gd::Variable* currentVariable = &variable;
|
||||
|
||||
// Walk until size - 1 as we want the last parent.
|
||||
for (size_t index = startIndex; index + 1 < childVariableNames.size();
|
||||
++index) {
|
||||
const gd::String& childName = childVariableNames[index];
|
||||
|
||||
if (childName.empty()) {
|
||||
if (currentVariable->GetChildrenCount() == 0) {
|
||||
// The array or structure is empty, we can't walk through it - there
|
||||
// is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
if (currentVariable->GetType() == gd::Variable::Array) {
|
||||
currentVariable = ¤tVariable->GetAtIndex(0);
|
||||
} else {
|
||||
currentVariable =
|
||||
currentVariable->GetAllChildren().begin()->second.get();
|
||||
}
|
||||
} else {
|
||||
if (!currentVariable->HasChild(childName)) {
|
||||
// Non existing child - there is no "parent".
|
||||
return {};
|
||||
}
|
||||
|
||||
currentVariable = ¤tVariable->GetChild(childName);
|
||||
}
|
||||
}
|
||||
|
||||
// Return the last parent of the chain of variables (so not the last
|
||||
// variable but the one before it).
|
||||
return {.parentVariable = currentVariable};
|
||||
}
|
||||
|
||||
VariableAndItsParent WalkUntilLastParent(
|
||||
const gd::VariablesContainer& variablesContainer,
|
||||
const std::vector<gd::String>& childVariableNames) {
|
||||
if (bailOutBecauseEmptyVariableName)
|
||||
return {}; // Do not even attempt to find the parent if we had an issue
|
||||
// when visiting nodes.
|
||||
|
||||
if (variableName.empty())
|
||||
return {}; // There is no "parent" to the variables container itself.
|
||||
|
||||
const gd::Variable* variable = variablesContainer.Has(variableName)
|
||||
? &variablesContainer.Get(variableName)
|
||||
: nullptr;
|
||||
if (childVariableNames.empty() || !variable)
|
||||
return {// No child: the parent is the variables container itself.
|
||||
.parentVariablesContainer = &variablesContainer};
|
||||
|
||||
return WalkUntilLastParent(*variable, childVariableNames, 0);
|
||||
}
|
||||
|
||||
const gd::Platform& platform;
|
||||
const gd::ProjectScopedContainers& projectScopedContainers;
|
||||
const gd::String& parameterType;
|
||||
gd::String& objectName;
|
||||
const gd::ExpressionNode* lastNodeToCheck;
|
||||
|
||||
const gd::VariablesContainer* variablesContainer;
|
||||
gd::String variableName;
|
||||
std::vector<gd::String> childVariableNames;
|
||||
bool bailOutBecauseEmptyVariableName;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -20,14 +20,9 @@ namespace gd {
|
||||
|
||||
void EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsFunctionsContainer functionContainer,
|
||||
const gd::EventsFunctionsContainer& functionContainer,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// Functions don't have access to objects from the "outer" scope.
|
||||
outputGlobalObjectsContainer.GetObjects().clear();
|
||||
outputGlobalObjectsContainer.GetObjectGroups().Clear();
|
||||
|
||||
// Functions scope for objects is defined according
|
||||
// to parameters
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
@@ -45,13 +40,11 @@ void EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// The context is build the same way as free function...
|
||||
FreeEventsFunctionToObjectsContainer(project,
|
||||
eventsBasedBehavior.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
outputGlobalObjectsContainer,
|
||||
outputObjectsContainer);
|
||||
|
||||
// ...and has an "Object" by convention...
|
||||
@@ -83,13 +76,11 @@ void EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
// The context is build the same way as free function...
|
||||
FreeEventsFunctionToObjectsContainer(project,
|
||||
eventsBasedObject.GetEventsFunctions(),
|
||||
eventsFunction,
|
||||
outputGlobalObjectsContainer,
|
||||
outputObjectsContainer);
|
||||
|
||||
// TODO EBO Use a constant instead a hard coded value "Object".
|
||||
@@ -101,17 +92,30 @@ void EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
"its parameters).");
|
||||
return;
|
||||
}
|
||||
if (eventsBasedObject.HasObjectNamed("Object")) {
|
||||
if (eventsBasedObject.GetObjects().HasObjectNamed("Object")) {
|
||||
gd::LogWarning("Child-objects can't be named Object because it's reserved"
|
||||
"for the parent. ");
|
||||
return;
|
||||
}
|
||||
|
||||
// ...and its children.
|
||||
auto &children = eventsBasedObject.GetObjects();
|
||||
gd::EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
eventsBasedObject, outputObjectsContainer);
|
||||
}
|
||||
|
||||
void EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
gd::ObjectsContainer& outputObjectsContainer) {
|
||||
auto &children = eventsBasedObject.GetObjects().GetObjects();
|
||||
for (auto &childObject : children) {
|
||||
auto child = childObject.get();
|
||||
outputObjectsContainer.InsertObject(*child, children.size());
|
||||
outputObjectsContainer.InsertObject(
|
||||
*child, outputObjectsContainer.GetObjectsCount());
|
||||
}
|
||||
auto &childrenGroups = eventsBasedObject.GetObjects().GetObjectGroups();
|
||||
for (size_t index = 0; index < childrenGroups.Count(); ++index) {
|
||||
auto &childGroup = childrenGroups.Get(index);
|
||||
outputObjectsContainer.GetObjectGroups().Insert(
|
||||
childGroup, outputObjectsContainer.GetObjectGroups().Count());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -3,11 +3,11 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#if defined(GD_IDE_ONLY)
|
||||
#ifndef EventsFunctionTools_H
|
||||
#define EventsFunctionTools_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class EventsFunctionsContainer;
|
||||
@@ -35,10 +35,10 @@ class GD_CORE_API EventsFunctionTools {
|
||||
*/
|
||||
static void FreeEventsFunctionToObjectsContainer(
|
||||
const gd::Project& project,
|
||||
const gd::EventsFunctionsContainer functionContainer,
|
||||
const gd::EventsFunctionsContainer& functionContainer,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
|
||||
/**
|
||||
* \brief Given a behavior events function, initialize the given objects container
|
||||
* with objects described in the events function parameters, in
|
||||
@@ -52,8 +52,8 @@ class GD_CORE_API EventsFunctionTools {
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
|
||||
/**
|
||||
* \brief Given a parent-object events function, initialize the given objects container
|
||||
* with objects described in the events function parameters, in
|
||||
@@ -67,10 +67,10 @@ class GD_CORE_API EventsFunctionTools {
|
||||
const gd::Project& project,
|
||||
const gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& outputGlobalObjectsContainer,
|
||||
gd::ObjectsContainer& outputObjectsContainer);
|
||||
|
||||
static void CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ObjectsContainer &outputObjectsContainer);
|
||||
};
|
||||
} // namespace gd
|
||||
|
||||
#endif // EventsFunctionTools_H
|
||||
#endif
|
||||
|
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "EventsBasedObjectDependencyFinder.h"
|
||||
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
|
||||
namespace gd {
|
||||
bool EventsBasedObjectDependencyFinder::IsDependentFromEventsBasedObject(
|
||||
const gd::Project &project, const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::EventsBasedObject &dependency) {
|
||||
return gd::EventsBasedObjectDependencyFinder::
|
||||
IsDependentFromEventsBasedObject(project, eventsBasedObject, dependency,
|
||||
0);
|
||||
}
|
||||
bool EventsBasedObjectDependencyFinder::IsDependentFromEventsBasedObject(
|
||||
const gd::Project &project, const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::EventsBasedObject &dependency, int depth) {
|
||||
|
||||
if (&eventsBasedObject == &dependency) {
|
||||
return true;
|
||||
}
|
||||
if (depth > 200) {
|
||||
return false;
|
||||
}
|
||||
for (auto &object : eventsBasedObject.GetObjects().GetObjects()) {
|
||||
const gd::String &objectType = object->GetType();
|
||||
if (project.HasEventsBasedObject(objectType) &&
|
||||
gd::EventsBasedObjectDependencyFinder::IsDependentFromEventsBasedObject(
|
||||
project, project.GetEventsBasedObject(objectType), dependency,
|
||||
depth + 1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace gd
|
37
Core/GDCore/IDE/Project/EventsBasedObjectDependencyFinder.h
Normal file
37
Core/GDCore/IDE/Project/EventsBasedObjectDependencyFinder.h
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* GDevelop JS Platform
|
||||
* Copyright 2008-2023 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class EventsBasedObject;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Find resource usages in several parts of the project.
|
||||
*
|
||||
* \ingroup IDE
|
||||
*/
|
||||
class EventsBasedObjectDependencyFinder {
|
||||
public:
|
||||
static bool IsDependentFromEventsBasedObject(
|
||||
const gd::Project &project,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::EventsBasedObject &dependency);
|
||||
|
||||
private:
|
||||
static bool IsDependentFromEventsBasedObject(
|
||||
const gd::Project &project,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::EventsBasedObject &dependency, int depth);
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -148,12 +148,6 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
|
||||
gd::ArbitraryEventsWorker &worker) {
|
||||
// Add (free) events functions
|
||||
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
project, eventsFunctionsExtension, *eventsFunction,
|
||||
globalObjectsAndGroups, objectsAndGroups);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents());
|
||||
}
|
||||
|
||||
@@ -176,14 +170,11 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
// Add (free) events functions
|
||||
for (auto &&eventsFunction : eventsFunctionsExtension.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
project, eventsFunctionsExtension, *eventsFunction,
|
||||
globalObjectsAndGroups, objectsAndGroups);
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddParameters(eventsFunction->GetParametersForEvents(eventsFunctionsExtension));
|
||||
gd::ObjectsContainer parameterObjectsContainer;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
project, eventsFunctionsExtension, *eventsFunction,
|
||||
parameterObjectsContainer);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
|
||||
}
|
||||
@@ -192,13 +183,13 @@ void ProjectBrowserHelper::ExposeEventsFunctionsExtensionEvents(
|
||||
for (auto &&eventsBasedBehavior :
|
||||
eventsFunctionsExtension.GetEventsBasedBehaviors()
|
||||
.GetInternalVector()) {
|
||||
ExposeEventsBasedBehaviorEvents(project, *eventsBasedBehavior, worker);
|
||||
ExposeEventsBasedBehaviorEvents(project, eventsFunctionsExtension, *eventsBasedBehavior, worker);
|
||||
}
|
||||
|
||||
// Add (object) events functions
|
||||
for (auto &&eventsBasedObject :
|
||||
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
|
||||
ExposeEventsBasedObjectEvents(project, *eventsBasedObject, worker);
|
||||
ExposeEventsBasedObjectEvents(project, eventsFunctionsExtension, *eventsBasedObject, worker);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,20 +203,17 @@ void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
gd::Project &project, const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
auto &behaviorEventsFunctions = eventsBasedBehavior.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : behaviorEventsFunctions.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
project, eventsBasedBehavior, *eventsFunction, globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddPropertiesContainer(eventsBasedBehavior.GetSharedPropertyDescriptors());
|
||||
projectScopedContainers.AddPropertiesContainer(eventsBasedBehavior.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction->GetParametersForEvents(eventsBasedBehavior.GetEventsFunctions()));
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
*eventsFunction, parameterObjectsContainers);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
|
||||
}
|
||||
@@ -236,30 +224,23 @@ void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
gd::ArbitraryEventsWorker &worker) {
|
||||
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
project, eventsBasedObject, *eventsFunction, globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents());
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
gd::Project &project, const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) {
|
||||
auto &objectEventsFunctions = eventsBasedObject.GetEventsFunctions();
|
||||
for (auto &&eventsFunction : objectEventsFunctions.GetInternalVector()) {
|
||||
gd::ObjectsContainer globalObjectsAndGroups;
|
||||
gd::ObjectsContainer objectsAndGroups;
|
||||
gd::EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
project, eventsBasedObject, *eventsFunction, globalObjectsAndGroups,
|
||||
objectsAndGroups);
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(globalObjectsAndGroups, objectsAndGroups);
|
||||
projectScopedContainers.AddPropertiesContainer(eventsBasedObject.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction->GetParametersForEvents(eventsBasedObject.GetEventsFunctions()));
|
||||
|
||||
gd::ObjectsContainer parameterObjectsContainers;
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
project, eventsFunctionsExtension, eventsBasedObject,
|
||||
*eventsFunction, parameterObjectsContainers);
|
||||
|
||||
worker.Launch(eventsFunction->GetEvents(), projectScopedContainers);
|
||||
}
|
||||
@@ -269,7 +250,7 @@ void ProjectBrowserHelper::ExposeProjectObjects(
|
||||
gd::Project &project, gd::ArbitraryObjectsWorker &worker) {
|
||||
|
||||
// Global objects
|
||||
worker.Launch(project);
|
||||
worker.Launch(project.GetObjects());
|
||||
|
||||
// Layout objects
|
||||
for (size_t i = 0; i < project.GetLayoutsCount(); i++) {
|
||||
@@ -284,7 +265,7 @@ void ProjectBrowserHelper::ExposeProjectObjects(
|
||||
for (auto &&eventsBasedObjectUniquePtr :
|
||||
eventsFunctionsExtension.GetEventsBasedObjects().GetInternalVector()) {
|
||||
auto eventsBasedObject = eventsBasedObjectUniquePtr.get();
|
||||
worker.Launch(*eventsBasedObject);
|
||||
worker.Launch(eventsBasedObject->GetObjects());
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -294,7 +275,7 @@ void ProjectBrowserHelper::ExposeLayoutObjects(gd::Layout &layout,
|
||||
// In the future, layouts may have children object containers.
|
||||
|
||||
// Layout objects
|
||||
worker.Launch(layout);
|
||||
worker.Launch(layout.GetObjects());
|
||||
}
|
||||
|
||||
void ProjectBrowserHelper::ExposeProjectFunctions(
|
||||
|
@@ -122,7 +122,9 @@ public:
|
||||
* event-based behavior.
|
||||
*/
|
||||
static void ExposeEventsBasedBehaviorEvents(
|
||||
gd::Project &project, const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
|
||||
/**
|
||||
@@ -144,10 +146,11 @@ public:
|
||||
* This should be the preferred way to traverse all the events of an
|
||||
* event-based object.
|
||||
*/
|
||||
static void
|
||||
ExposeEventsBasedObjectEvents(gd::Project &project,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
static void ExposeEventsBasedObjectEvents(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker);
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all ObjectContainers of the project
|
||||
|
@@ -17,7 +17,7 @@
|
||||
namespace gd {
|
||||
|
||||
void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
|
||||
project.GetObjectGroups().Clear();
|
||||
project.GetObjects().GetObjectGroups().Clear();
|
||||
while (project.GetExternalEventsCount() > 0)
|
||||
project.RemoveExternalEvents(project.GetExternalEvents(0).GetName());
|
||||
|
||||
@@ -26,18 +26,30 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
|
||||
wholeProjectBrowser.ExposeObjects(project, behaviorDefaultFlagClearer);
|
||||
|
||||
for (unsigned int i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
project.GetLayout(i).GetObjectGroups().Clear();
|
||||
project.GetLayout(i).GetObjects().GetObjectGroups().Clear();
|
||||
project.GetLayout(i).GetEvents().Clear();
|
||||
}
|
||||
|
||||
// Keep the EventsBasedObject object list because it's useful for the Runtime
|
||||
// Keep:
|
||||
// - the EventsBasedObject object list because it's useful for the Runtime
|
||||
// to create the child-object.
|
||||
// - the globalVariables and sceneVariables
|
||||
for (unsigned int extensionIndex = 0;
|
||||
extensionIndex < project.GetEventsFunctionsExtensionsCount();
|
||||
++extensionIndex) {
|
||||
auto &extension = project.GetEventsFunctionsExtension(extensionIndex);
|
||||
extension.SetFullName("");
|
||||
extension.SetShortDescription("");
|
||||
extension.SetDescription("");
|
||||
extension.SetHelpPath("");
|
||||
extension.SetIconUrl("");
|
||||
extension.SetPreviewIconUrl("");
|
||||
extension.SetOrigin("", "");
|
||||
extension.SetVersion("");
|
||||
auto &eventsBasedObjects = extension.GetEventsBasedObjects();
|
||||
if (eventsBasedObjects.size() == 0) {
|
||||
if (eventsBasedObjects.size() == 0 &&
|
||||
extension.GetGlobalVariables().Count() == 0 &&
|
||||
extension.GetSceneVariables().Count() == 0) {
|
||||
project.RemoveEventsFunctionsExtension(extension.GetName());
|
||||
extensionIndex--;
|
||||
continue;
|
||||
@@ -51,6 +63,7 @@ void GD_CORE_API ProjectStripper::StripProjectForExport(gd::Project &project) {
|
||||
eventsBasedObject.GetPropertyDescriptors().GetInternalVector().clear();
|
||||
}
|
||||
extension.GetEventsBasedBehaviors().Clear();
|
||||
extension.ClearEventsFunctions();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -76,7 +76,7 @@ void ResourceExposer::ExposeWholeProjectResources(gd::Project& project, gd::Arbi
|
||||
void ResourceExposer::ExposeProjectResources(gd::Project& project, gd::ArbitraryResourceWorker& worker) {
|
||||
// Expose global objects configuration resources
|
||||
auto objectWorker = gd::GetResourceWorkerOnObjects(project, worker);
|
||||
objectWorker.Launch(project);
|
||||
objectWorker.Launch(project.GetObjects());
|
||||
}
|
||||
|
||||
void ResourceExposer::ExposeLayoutResources(
|
||||
|
241
Core/GDCore/IDE/VariableInstructionSwitcher.cpp
Normal file
241
Core/GDCore/IDE/VariableInstructionSwitcher.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "VariableInstructionSwitcher.h"
|
||||
|
||||
#include "GDCore/Events/Instruction.h"
|
||||
#include "GDCore/IDE/Events/ExpressionVariablePathFinder.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
const gd::String VariableInstructionSwitcher::variableGetterIdentifier =
|
||||
"NumberVariable";
|
||||
const gd::String VariableInstructionSwitcher::variableSetterIdentifier =
|
||||
"SetNumberVariable";
|
||||
const gd::String VariableInstructionSwitcher::variablePushIdentifier =
|
||||
"PushNumber";
|
||||
const gd::String VariableInstructionSwitcher::objectVariableGetterIdentifier =
|
||||
"NumberObjectVariable";
|
||||
const gd::String VariableInstructionSwitcher::objectVariableSetterIdentifier =
|
||||
"SetNumberObjectVariable";
|
||||
const gd::String VariableInstructionSwitcher::objectVariablePushIdentifier =
|
||||
"PushNumberToObjectVariable";
|
||||
const gd::String VariableInstructionSwitcher::unknownInstructionIdentifier = "";
|
||||
|
||||
bool VariableInstructionSwitcher::IsSwitchableVariableInstruction(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberVariable" ||
|
||||
instructionType == "StringVariable" ||
|
||||
instructionType == "BooleanVariable" ||
|
||||
|
||||
instructionType == "SetNumberVariable" ||
|
||||
instructionType == "SetStringVariable" ||
|
||||
instructionType == "SetBooleanVariable" ||
|
||||
|
||||
instructionType == "PushNumber" || instructionType == "PushString" ||
|
||||
instructionType == "PushBoolean" ||
|
||||
|
||||
IsSwitchableObjectVariableInstruction(instructionType);
|
||||
}
|
||||
|
||||
bool VariableInstructionSwitcher::IsSwitchableObjectVariableInstruction(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberObjectVariable" ||
|
||||
instructionType == "StringObjectVariable" ||
|
||||
instructionType == "BooleanObjectVariable" ||
|
||||
|
||||
instructionType == "SetNumberObjectVariable" ||
|
||||
instructionType == "SetStringObjectVariable" ||
|
||||
instructionType == "SetBooleanObjectVariable" ||
|
||||
|
||||
instructionType == "PushNumberToObjectVariable" ||
|
||||
instructionType == "PushStringToObjectVariable" ||
|
||||
instructionType == "PushBooleanToObjectVariable";
|
||||
}
|
||||
|
||||
const gd::String &
|
||||
VariableInstructionSwitcher::GetSwitchableVariableInstructionIdentifier(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberVariable" ||
|
||||
instructionType == "StringVariable" ||
|
||||
instructionType == "BooleanVariable"
|
||||
? VariableInstructionSwitcher::variableGetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "SetNumberVariable" ||
|
||||
instructionType == "SetStringVariable" ||
|
||||
instructionType == "SetBooleanVariable"
|
||||
? VariableInstructionSwitcher::variableSetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "PushNumber" || instructionType == "PushString" ||
|
||||
instructionType == "PushBoolean"
|
||||
? VariableInstructionSwitcher::variablePushIdentifier
|
||||
:
|
||||
|
||||
instructionType == "NumberObjectVariable" ||
|
||||
instructionType == "StringObjectVariable" ||
|
||||
instructionType == "BooleanObjectVariable"
|
||||
? VariableInstructionSwitcher::objectVariableGetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "SetNumberObjectVariable" ||
|
||||
instructionType == "SetStringObjectVariable" ||
|
||||
instructionType == "SetBooleanObjectVariable"
|
||||
? VariableInstructionSwitcher::objectVariableSetterIdentifier
|
||||
:
|
||||
|
||||
instructionType == "PushNumberToObjectVariable" ||
|
||||
instructionType == "PushStringToObjectVariable" ||
|
||||
instructionType == "PushBooleanToObjectVariable"
|
||||
? VariableInstructionSwitcher::objectVariablePushIdentifier
|
||||
:
|
||||
|
||||
VariableInstructionSwitcher::unknownInstructionIdentifier;
|
||||
}
|
||||
|
||||
const gd::Variable::Type
|
||||
VariableInstructionSwitcher::GetSwitchableInstructionVariableType(
|
||||
const gd::String &instructionType) {
|
||||
return instructionType == "NumberVariable" ||
|
||||
instructionType == "SetNumberVariable" ||
|
||||
instructionType == "PushNumber" ||
|
||||
instructionType == "NumberObjectVariable" ||
|
||||
instructionType == "SetNumberObjectVariable" ||
|
||||
instructionType == "PushNumberToObjectVariable"
|
||||
? gd::Variable::Number
|
||||
:
|
||||
|
||||
instructionType == "StringVariable" ||
|
||||
instructionType == "SetStringVariable" ||
|
||||
instructionType == "PushString" ||
|
||||
instructionType == "StringObjectVariable" ||
|
||||
instructionType == "SetStringObjectVariable" ||
|
||||
instructionType == "PushStringToObjectVariable"
|
||||
? gd::Variable::String
|
||||
:
|
||||
|
||||
instructionType == "BooleanVariable" ||
|
||||
instructionType == "SetBooleanVariable" ||
|
||||
instructionType == "PushBoolean" ||
|
||||
instructionType == "BooleanObjectVariable" ||
|
||||
instructionType == "SetBooleanObjectVariable" ||
|
||||
instructionType == "PushBooleanToObjectVariable"
|
||||
? gd::Variable::Boolean
|
||||
:
|
||||
|
||||
gd::Variable::Unknown;
|
||||
}
|
||||
|
||||
void VariableInstructionSwitcher::SwitchVariableInstructionType(
|
||||
gd::Instruction &instruction, const gd::Variable::Type variableType) {
|
||||
if (instruction.GetType() == "NumberVariable" ||
|
||||
instruction.GetType() == "StringVariable" ||
|
||||
instruction.GetType() == "BooleanVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("NumberVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("StringVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("BooleanVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "SetNumberVariable" ||
|
||||
instruction.GetType() == "SetStringVariable" ||
|
||||
instruction.GetType() == "SetBooleanVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("SetNumberVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("SetStringVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("SetBooleanVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "PushNumber" ||
|
||||
instruction.GetType() == "PushString" ||
|
||||
instruction.GetType() == "PushBoolean") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("PushNumber");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("PushString");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("PushBoolean");
|
||||
}
|
||||
} else if (instruction.GetType() == "NumberObjectVariable" ||
|
||||
instruction.GetType() == "StringObjectVariable" ||
|
||||
instruction.GetType() == "BooleanObjectVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("NumberObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("StringObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("BooleanObjectVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "SetNumberObjectVariable" ||
|
||||
instruction.GetType() == "SetStringObjectVariable" ||
|
||||
instruction.GetType() == "SetBooleanObjectVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("SetNumberObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("SetStringObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("SetBooleanObjectVariable");
|
||||
}
|
||||
} else if (instruction.GetType() == "PushNumberToObjectVariable" ||
|
||||
instruction.GetType() == "PushStringToObjectVariable" ||
|
||||
instruction.GetType() == "PushBooleanToObjectVariable") {
|
||||
if (variableType == gd::Variable::Type::Number) {
|
||||
instruction.SetType("PushNumberToObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::String) {
|
||||
instruction.SetType("PushStringToObjectVariable");
|
||||
} else if (variableType == gd::Variable::Type::Boolean) {
|
||||
instruction.SetType("PushBooleanToObjectVariable");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const gd::Variable::Type
|
||||
VariableInstructionSwitcher::GetVariableTypeFromParameters(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
const gd::Instruction &instruction) {
|
||||
if (instruction.GetParametersCount() < 2 ||
|
||||
!gd::VariableInstructionSwitcher::IsSwitchableVariableInstruction(
|
||||
instruction.GetType())) {
|
||||
return gd::Variable::Type::Unknown;
|
||||
}
|
||||
const bool isObjectVariable =
|
||||
gd::VariableInstructionSwitcher::IsSwitchableObjectVariableInstruction(
|
||||
instruction.GetType());
|
||||
const gd::String &objectName =
|
||||
isObjectVariable ? instruction.GetParameter(0).GetPlainString() : "";
|
||||
|
||||
const std::size_t variableParameterIndex = isObjectVariable ? 1 : 0;
|
||||
auto &variableExpressionNode =
|
||||
*instruction.GetParameter(variableParameterIndex).GetRootNode();
|
||||
|
||||
auto variableType = gd::ExpressionVariablePathFinder::GetVariableType(
|
||||
platform, projectScopedContainers, variableExpressionNode, objectName);
|
||||
return variableType == gd::Variable::Type::Array
|
||||
? // "Push" actions need the child type to be able to switch.
|
||||
gd::ExpressionVariablePathFinder::GetArrayVariableType(
|
||||
platform, projectScopedContainers, variableExpressionNode,
|
||||
objectName)
|
||||
: variableType;
|
||||
}
|
||||
|
||||
void VariableInstructionSwitcher::SwitchBetweenUnifiedInstructionIfNeeded(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::Instruction &instruction) {
|
||||
const auto variableType =
|
||||
gd::VariableInstructionSwitcher::GetVariableTypeFromParameters(
|
||||
platform, projectScopedContainers, instruction);
|
||||
if (variableType != gd::Variable::Type::Unknown) {
|
||||
gd::VariableInstructionSwitcher::SwitchVariableInstructionType(
|
||||
instruction, variableType);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
91
Core/GDCore/IDE/VariableInstructionSwitcher.h
Normal file
91
Core/GDCore/IDE/VariableInstructionSwitcher.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#pragma once
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class Instruction;
|
||||
class Platform;
|
||||
class ProjectScopedContainers;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
/**
|
||||
* Events set and check variables with sets of 3 instructions for:
|
||||
* - number
|
||||
* - string
|
||||
* - boolean
|
||||
*
|
||||
* Users only see 1 instruction. The editor automatically switches between the 3
|
||||
* instructions according to the variable type.
|
||||
*/
|
||||
class GD_CORE_API VariableInstructionSwitcher {
|
||||
public:
|
||||
/**
|
||||
* \brief Return true if the instruction is a variable getter or setter
|
||||
* (including object variable instructions).
|
||||
*/
|
||||
static bool
|
||||
IsSwitchableVariableInstruction(const gd::String &instructionType);
|
||||
|
||||
/**
|
||||
* \brief Return true if the instruction is an object variable getter or
|
||||
* setter.
|
||||
*/
|
||||
static bool
|
||||
IsSwitchableObjectVariableInstruction(const gd::String &instructionType);
|
||||
|
||||
/**
|
||||
* \brief Return the common identifier for variable getter or setter or an
|
||||
* empty string otherwise.
|
||||
*
|
||||
* The instruction type of the "number" one is actually used as the common
|
||||
* identifier.
|
||||
*/
|
||||
static const gd::String &
|
||||
GetSwitchableVariableInstructionIdentifier(const gd::String &instructionType);
|
||||
|
||||
/**
|
||||
* \brief Return the variable type for variable getter or setter.
|
||||
*/
|
||||
static const gd::Variable::Type
|
||||
GetSwitchableInstructionVariableType(const gd::String &instructionType);
|
||||
|
||||
/**
|
||||
* \brief Modify the instruction type to match the given variable type.
|
||||
*/
|
||||
static void
|
||||
SwitchVariableInstructionType(gd::Instruction &instruction,
|
||||
const gd::Variable::Type variableType);
|
||||
|
||||
/**
|
||||
* \brief Return the variable type of the instruction parameter.
|
||||
*/
|
||||
static const gd::Variable::Type GetVariableTypeFromParameters(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
const gd::Instruction &instruction);
|
||||
|
||||
/**
|
||||
* \brief Modify the instruction type to match the variable type of the
|
||||
* instruction parameter.
|
||||
*/
|
||||
static void SwitchBetweenUnifiedInstructionIfNeeded(
|
||||
const gd::Platform &platform,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::Instruction &instruction);
|
||||
|
||||
private:
|
||||
static const gd::String variableGetterIdentifier;
|
||||
static const gd::String variableSetterIdentifier;
|
||||
static const gd::String variablePushIdentifier;
|
||||
static const gd::String objectVariableGetterIdentifier;
|
||||
static const gd::String objectVariableSetterIdentifier;
|
||||
static const gd::String objectVariablePushIdentifier;
|
||||
static const gd::String unknownInstructionIdentifier;
|
||||
};
|
||||
} // namespace gd
|
@@ -19,12 +19,14 @@
|
||||
#include "GDCore/IDE/Events/EventsPropertyReplacer.h"
|
||||
#include "GDCore/IDE/Events/EventsRefactorer.h"
|
||||
#include "GDCore/IDE/Events/EventsVariableReplacer.h"
|
||||
#include "GDCore/IDE/Events/EventsVariableInstructionTypeSwitcher.h"
|
||||
#include "GDCore/IDE/Events/ExpressionsParameterMover.h"
|
||||
#include "GDCore/IDE/Events/ExpressionsRenamer.h"
|
||||
#include "GDCore/IDE/Events/InstructionsParameterMover.h"
|
||||
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/LinkEventTargetRenamer.h"
|
||||
#include "GDCore/IDE/Events/ProjectElementRenamer.h"
|
||||
#include "GDCore/IDE/Events/BehaviorParametersFiller.h"
|
||||
#include "GDCore/IDE/EventsFunctionTools.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
|
||||
@@ -84,10 +86,10 @@ WholeProjectRefactorer::GetAllObjectTypesUsingEventsBasedBehavior(
|
||||
}
|
||||
};
|
||||
|
||||
addTypesOfObjectsIn(project);
|
||||
addTypesOfObjectsIn(project.GetObjects());
|
||||
for (std::size_t s = 0; s < project.GetLayoutsCount(); s++) {
|
||||
auto &layout = project.GetLayout(s);
|
||||
addTypesOfObjectsIn(layout);
|
||||
addTypesOfObjectsIn(layout.GetObjects());
|
||||
}
|
||||
|
||||
return allTypes;
|
||||
@@ -140,7 +142,6 @@ void WholeProjectRefactorer::EnsureObjectEventsFunctionsProperParameters(
|
||||
|
||||
VariablesChangeset
|
||||
WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
gd::Project &project,
|
||||
const gd::SerializerElement &oldSerializedVariablesContainer,
|
||||
const gd::VariablesContainer &newVariablesContainer) {
|
||||
gd::VariablesChangeset changeset;
|
||||
@@ -180,6 +181,20 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
changeset.oldToNewVariableNames[oldName] = variableName;
|
||||
}
|
||||
|
||||
const auto &oldVariable = oldVariablesContainer.Get(oldName);
|
||||
if (gd::WholeProjectRefactorer::HasAnyVariableTypeChanged(oldVariable, variable)) {
|
||||
changeset.typeChangedVariableNames.insert(variableName);
|
||||
}
|
||||
|
||||
const auto &variablesRenamingChangesetNode =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariable(oldVariable,
|
||||
variable);
|
||||
|
||||
if (variablesRenamingChangesetNode) {
|
||||
changeset.modifiedVariables[oldName] =
|
||||
std::move(variablesRenamingChangesetNode);
|
||||
}
|
||||
|
||||
// Renamed or not, this is not a removed variable.
|
||||
removedUuidAndNames.erase(variable.GetPersistentUuid());
|
||||
}
|
||||
@@ -192,14 +207,124 @@ WholeProjectRefactorer::ComputeChangesetForVariablesContainer(
|
||||
return changeset;
|
||||
}
|
||||
|
||||
std::shared_ptr<VariablesRenamingChangesetNode>
|
||||
WholeProjectRefactorer::ComputeChangesetForVariable(
|
||||
const gd::Variable &oldVariable, const gd::Variable &newVariable) {
|
||||
|
||||
if (newVariable.GetChildrenCount() == 0 ||
|
||||
oldVariable.GetChildrenCount() == 0) {
|
||||
return std::shared_ptr<VariablesRenamingChangesetNode>(nullptr);
|
||||
}
|
||||
|
||||
std::unordered_map<gd::String, gd::String> oldVariableNamesByUuid;
|
||||
for (const auto &pair : oldVariable.GetAllChildren()) {
|
||||
const auto &oldName = pair.first;
|
||||
const auto oldChild = pair.second;
|
||||
|
||||
// All variables are candidate to be removed.
|
||||
oldVariableNamesByUuid[oldChild->GetPersistentUuid()] = oldName;
|
||||
}
|
||||
|
||||
auto changeset = std::make_shared<VariablesRenamingChangesetNode>();
|
||||
for (const auto &pair : newVariable.GetAllChildren()) {
|
||||
const auto &newName = pair.first;
|
||||
const auto newChild = pair.second;
|
||||
|
||||
auto existingOldVariableUuidAndName =
|
||||
oldVariableNamesByUuid.find(newChild->GetPersistentUuid());
|
||||
if (existingOldVariableUuidAndName == oldVariableNamesByUuid.end()) {
|
||||
// This is a new variable.
|
||||
continue;
|
||||
}
|
||||
const gd::String &oldName = existingOldVariableUuidAndName->second;
|
||||
const auto &oldChild = oldVariable.GetChild(oldName);
|
||||
|
||||
if (oldName != newName) {
|
||||
// This is a renamed child.
|
||||
changeset->oldToNewVariableNames[oldName] = newName;
|
||||
}
|
||||
|
||||
const auto &childChangeset =
|
||||
gd::WholeProjectRefactorer::ComputeChangesetForVariable(oldChild,
|
||||
*newChild);
|
||||
if (childChangeset) {
|
||||
changeset->modifiedVariables[oldName] = std::move(childChangeset);
|
||||
}
|
||||
}
|
||||
if (changeset->modifiedVariables.size() == 0 &&
|
||||
changeset->oldToNewVariableNames.size() == 0) {
|
||||
return std::shared_ptr<VariablesRenamingChangesetNode>(nullptr);
|
||||
}
|
||||
return std::move(changeset);
|
||||
};
|
||||
|
||||
bool WholeProjectRefactorer::HasAnyVariableTypeChanged(
|
||||
const gd::Variable &oldVariable, const gd::Variable &newVariable) {
|
||||
if (newVariable.GetType() != oldVariable.GetType()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (newVariable.GetChildrenCount() == 0 ||
|
||||
oldVariable.GetChildrenCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unordered_map<gd::String, gd::String> oldVariableNamesByUuid;
|
||||
for (const auto &pair : oldVariable.GetAllChildren()) {
|
||||
const auto &oldName = pair.first;
|
||||
const auto oldChild = pair.second;
|
||||
|
||||
// All variables are candidate to be removed.
|
||||
oldVariableNamesByUuid[oldChild->GetPersistentUuid()] = oldName;
|
||||
}
|
||||
|
||||
for (const auto &pair : newVariable.GetAllChildren()) {
|
||||
const auto &newName = pair.first;
|
||||
const auto newChild = pair.second;
|
||||
|
||||
auto existingOldVariableUuidAndName =
|
||||
oldVariableNamesByUuid.find(newChild->GetPersistentUuid());
|
||||
if (existingOldVariableUuidAndName == oldVariableNamesByUuid.end()) {
|
||||
// This is a new variable.
|
||||
continue;
|
||||
}
|
||||
const gd::String &oldName = existingOldVariableUuidAndName->second;
|
||||
const auto &oldChild = oldVariable.GetChild(oldName);
|
||||
|
||||
if (gd::WholeProjectRefactorer::HasAnyVariableTypeChanged(oldChild,
|
||||
*newChild)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ApplyRefactoringForVariablesContainer(
|
||||
gd::Project &project, const gd::VariablesContainer &newVariablesContainer,
|
||||
const gd::VariablesChangeset &changeset) {
|
||||
gd::Project &project, gd::VariablesContainer &variablesContainer,
|
||||
const gd::VariablesChangeset &changeset,
|
||||
const gd::SerializerElement &originalSerializedVariables) {
|
||||
// Revert changes
|
||||
gd::SerializerElement editedSerializedVariables;
|
||||
variablesContainer.SerializeTo(editedSerializedVariables);
|
||||
variablesContainer.UnserializeFrom(originalSerializedVariables);
|
||||
|
||||
// Rename and remove variables
|
||||
gd::EventsVariableReplacer eventsVariableReplacer(
|
||||
project.GetCurrentPlatform(), newVariablesContainer,
|
||||
changeset.oldToNewVariableNames, changeset.removedVariableNames);
|
||||
project.GetCurrentPlatform(), variablesContainer,
|
||||
changeset, changeset.removedVariableNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
eventsVariableReplacer);
|
||||
|
||||
// Apply back changes
|
||||
variablesContainer.UnserializeFrom(editedSerializedVariables);
|
||||
|
||||
// Switch types of instructions
|
||||
gd::EventsVariableInstructionTypeSwitcher
|
||||
eventsVariableInstructionTypeSwitcher(project.GetCurrentPlatform(),
|
||||
variablesContainer,
|
||||
changeset.typeChangedVariableNames);
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(
|
||||
project, eventsVariableInstructionTypeSwitcher);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedBehavior(
|
||||
@@ -208,7 +333,7 @@ void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedBehavior(
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &sourceExtensionName) {
|
||||
const EventBasedBehaviorBrowser eventBasedBehaviorExposer(
|
||||
eventsBasedBehavior);
|
||||
eventsFunctionsExtension, eventsBasedBehavior);
|
||||
WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
project, eventsFunctionsExtension, sourceExtensionName,
|
||||
eventsFunctionsExtension.GetName(), eventBasedBehaviorExposer);
|
||||
@@ -724,7 +849,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorProperty(
|
||||
oldPropertyName, newPropertyName);
|
||||
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsBasedBehavior, behaviorRenamer);
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior, behaviorRenamer);
|
||||
} else {
|
||||
// Properties that represent primitive values will be used through
|
||||
// their related actions/conditions/expressions. Rename these.
|
||||
@@ -794,7 +919,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehaviorSharedProperty(
|
||||
oldPropertyName, newPropertyName);
|
||||
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedBehaviorEvents(
|
||||
project, eventsBasedBehavior, behaviorRenamer);
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior, behaviorRenamer);
|
||||
} else {
|
||||
// Properties that represent primitive values will be used through
|
||||
// their related actions/conditions/expressions. Rename these.
|
||||
@@ -1052,12 +1177,14 @@ WholeProjectRefactorer::FindInvalidRequiredBehaviorProperties(
|
||||
};
|
||||
|
||||
// Find in global objects
|
||||
findInvalidRequiredBehaviorPropertiesInObjects(project.GetObjects());
|
||||
findInvalidRequiredBehaviorPropertiesInObjects(
|
||||
project.GetObjects().GetObjects());
|
||||
|
||||
// Find in layout objects.
|
||||
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
const gd::Layout &layout = project.GetLayout(i);
|
||||
findInvalidRequiredBehaviorPropertiesInObjects(layout.GetObjects());
|
||||
findInvalidRequiredBehaviorPropertiesInObjects(
|
||||
layout.GetObjects().GetObjects());
|
||||
}
|
||||
return invalidRequiredBehaviorProperties;
|
||||
}
|
||||
@@ -1391,53 +1518,38 @@ void WholeProjectRefactorer::DoRenameObject(
|
||||
projectBrowser.ExposeFunctions(project, objectParameterRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRemovedInLayout(
|
||||
gd::Project &project, gd::Layout &layout, const gd::String &objectName,
|
||||
bool isObjectGroup, bool removeEventsAndGroups) {
|
||||
void WholeProjectRefactorer::ObjectRemovedInLayout(
|
||||
gd::Project &project, gd::Layout &layout, const gd::String &objectName) {
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
|
||||
|
||||
// Remove object in the current layout
|
||||
if (removeEventsAndGroups) {
|
||||
gd::EventsRefactorer::RemoveObjectInEvents(project.GetCurrentPlatform(),
|
||||
projectScopedContainers,
|
||||
layout.GetEvents(), objectName);
|
||||
}
|
||||
if (!isObjectGroup) { // Object groups can't have instances or be in other
|
||||
// groups
|
||||
if (removeEventsAndGroups) {
|
||||
for (std::size_t g = 0; g < layout.GetObjectGroups().size(); ++g) {
|
||||
if (layout.GetObjectGroups()[g].Find(objectName))
|
||||
layout.GetObjectGroups()[g].RemoveObject(objectName);
|
||||
}
|
||||
}
|
||||
layout.GetInitialInstances().RemoveInitialInstancesOfObject(objectName);
|
||||
}
|
||||
|
||||
// Remove object in external events
|
||||
if (removeEventsAndGroups) {
|
||||
for (auto &externalEventsName :
|
||||
GetAssociatedExternalEvents(project, layout.GetName())) {
|
||||
auto &externalEvents = project.GetExternalEvents(externalEventsName);
|
||||
|
||||
gd::EventsRefactorer::RemoveObjectInEvents(
|
||||
project.GetCurrentPlatform(), projectScopedContainers,
|
||||
externalEvents.GetEvents(), objectName);
|
||||
}
|
||||
auto &groups = layout.GetObjects().GetObjectGroups();
|
||||
for (std::size_t g = 0; g < groups.size(); ++g) {
|
||||
if (groups[g].Find(objectName))
|
||||
groups[g].RemoveObject(objectName);
|
||||
}
|
||||
layout.GetInitialInstances().RemoveInitialInstancesOfObject(objectName);
|
||||
|
||||
// Remove object in external layouts
|
||||
if (!isObjectGroup) { // Object groups can't have instances
|
||||
std::vector<gd::String> externalLayoutsNames =
|
||||
GetAssociatedExternalLayouts(project, layout);
|
||||
for (gd::String name : externalLayoutsNames) {
|
||||
auto &externalLayout = project.GetExternalLayout(name);
|
||||
externalLayout.GetInitialInstances().RemoveInitialInstancesOfObject(
|
||||
objectName);
|
||||
}
|
||||
std::vector<gd::String> externalLayoutsNames =
|
||||
GetAssociatedExternalLayouts(project, layout);
|
||||
for (gd::String name : externalLayoutsNames) {
|
||||
auto &externalLayout = project.GetExternalLayout(name);
|
||||
externalLayout.GetInitialInstances().RemoveInitialInstancesOfObject(
|
||||
objectName);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::BehaviorsAddedToObjectInLayout(
|
||||
gd::Project &project, gd::Layout &layout, const gd::String &objectName) {
|
||||
auto projectScopedContainers = gd::ProjectScopedContainers::
|
||||
MakeNewProjectScopedContainersForProjectAndLayout(project, layout);
|
||||
gd::BehaviorParametersFiller behaviorParameterFiller(
|
||||
project.GetCurrentPlatform(), projectScopedContainers);
|
||||
gd::ProjectBrowserHelper::ExposeLayoutEventsAndExternalEvents(
|
||||
project, layout, behaviorParameterFiller);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
gd::Project &project, gd::Layout &layout, const gd::String &oldName,
|
||||
const gd::String &newName, bool isObjectGroup) {
|
||||
@@ -1452,11 +1564,12 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInLayout(
|
||||
project.GetCurrentPlatform(), projectScopedContainers, layout.GetEvents(),
|
||||
oldName, newName);
|
||||
|
||||
if (!isObjectGroup) { // Object groups can't have instances or be in other
|
||||
// groups
|
||||
// Object groups can't have instances or be in other groups
|
||||
if (!isObjectGroup) {
|
||||
auto &groups = layout.GetObjects().GetObjectGroups();
|
||||
layout.GetInitialInstances().RenameInstancesOfObject(oldName, newName);
|
||||
for (std::size_t g = 0; g < layout.GetObjectGroups().size(); ++g) {
|
||||
layout.GetObjectGroups()[g].RenameObject(oldName, newName);
|
||||
for (std::size_t g = 0; g < groups.size(); ++g) {
|
||||
groups[g].RenameObject(oldName, newName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1605,78 +1718,70 @@ void WholeProjectRefactorer::RenameObjectEffect(gd::Project &project,
|
||||
project, layout, projectElementRenamer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsBasedObject(
|
||||
void WholeProjectRefactorer::ObjectRemovedInEventsBasedObject(
|
||||
gd::Project &project, gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer, const gd::String &objectName,
|
||||
bool isObjectGroup, bool removeEventsAndGroups) {
|
||||
const gd::String &objectName) {
|
||||
for (auto &functionUniquePtr :
|
||||
eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
|
||||
auto function = functionUniquePtr.get();
|
||||
WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
|
||||
project, *function, globalObjectsContainer, objectsContainer,
|
||||
objectName, isObjectGroup, isObjectGroup);
|
||||
WholeProjectRefactorer::ObjectRemovedInEventsFunction(project, *function,
|
||||
objectName);
|
||||
}
|
||||
|
||||
auto &groups = eventsBasedObject.GetObjects().GetObjectGroups();
|
||||
for (std::size_t g = 0; g < groups.size(); ++g) {
|
||||
if (groups[g].Find(objectName))
|
||||
groups[g].RemoveObject(objectName);
|
||||
}
|
||||
eventsBasedObject.GetInitialInstances().RemoveInitialInstancesOfObject(
|
||||
objectName);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRemovedInEventsFunction(
|
||||
void WholeProjectRefactorer::ObjectRemovedInEventsFunction(
|
||||
gd::Project &project, gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer, const gd::String &objectName,
|
||||
bool isObjectGroup, bool removeEventsAndGroups) {
|
||||
// In theory we should pass a ProjectScopedContainers to this function so it
|
||||
// does not have to construct one. In practice, this is ok because we only
|
||||
// deal with objects.
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
|
||||
globalObjectsContainer, objectsContainer);
|
||||
const gd::String &objectName) {
|
||||
|
||||
if (removeEventsAndGroups) {
|
||||
gd::EventsRefactorer::RemoveObjectInEvents(
|
||||
project.GetCurrentPlatform(), projectScopedContainers,
|
||||
eventsFunction.GetEvents(), objectName);
|
||||
}
|
||||
if (!isObjectGroup) { // Object groups can't be in other groups
|
||||
if (removeEventsAndGroups) {
|
||||
for (std::size_t g = 0; g < eventsFunction.GetObjectGroups().size();
|
||||
++g) {
|
||||
if (eventsFunction.GetObjectGroups()[g].Find(objectName))
|
||||
eventsFunction.GetObjectGroups()[g].RemoveObject(objectName);
|
||||
}
|
||||
}
|
||||
for (std::size_t g = 0; g < eventsFunction.GetObjectGroups().size(); ++g) {
|
||||
if (eventsFunction.GetObjectGroups()[g].Find(objectName))
|
||||
eventsFunction.GetObjectGroups()[g].RemoveObject(objectName);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsBasedObject(
|
||||
gd::Project &project, gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::Project &project,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsBasedObject &eventsBasedObject, const gd::String &oldName,
|
||||
const gd::String &newName, bool isObjectGroup) {
|
||||
for (auto &functionUniquePtr :
|
||||
eventsBasedObject.GetEventsFunctions().GetInternalVector()) {
|
||||
auto *function = functionUniquePtr.get();
|
||||
WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
project, *function, globalObjectsContainer, eventsBasedObject, oldName,
|
||||
newName, isObjectGroup);
|
||||
project, projectScopedContainers, *function, oldName, newName,
|
||||
isObjectGroup);
|
||||
}
|
||||
|
||||
// Object groups can't have instances or be in other groups
|
||||
if (!isObjectGroup) {
|
||||
eventsBasedObject.GetInitialInstances().RenameInstancesOfObject(oldName,
|
||||
newName);
|
||||
auto &groups = eventsBasedObject.GetObjects().GetObjectGroups();
|
||||
for (std::size_t g = 0; g < groups.size(); ++g) {
|
||||
groups[g].RenameObject(oldName, newName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
gd::Project &project, gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer, const gd::String &oldName,
|
||||
gd::Project &project,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsFunction &eventsFunction, const gd::String &oldName,
|
||||
const gd::String &newName, bool isObjectGroup) {
|
||||
// In theory we should pass a ProjectScopedContainers to this function so it
|
||||
// does not have to construct one. In practice, this is ok because we only
|
||||
// deal with objects.
|
||||
auto projectScopedContainers =
|
||||
gd::ProjectScopedContainers::MakeNewProjectScopedContainersFor(
|
||||
globalObjectsContainer, objectsContainer);
|
||||
|
||||
gd::EventsRefactorer::RenameObjectInEvents(
|
||||
project.GetCurrentPlatform(), projectScopedContainers,
|
||||
eventsFunction.GetEvents(), oldName, newName);
|
||||
|
||||
if (!isObjectGroup) { // Object groups can't be in other groups
|
||||
// Object groups can't be in other groups
|
||||
if (!isObjectGroup) {
|
||||
for (std::size_t g = 0; g < eventsFunction.GetObjectGroups().size(); ++g) {
|
||||
eventsFunction.GetObjectGroups()[g].RenameObject(oldName, newName);
|
||||
}
|
||||
@@ -1686,15 +1791,18 @@ void WholeProjectRefactorer::ObjectOrGroupRenamedInEventsFunction(
|
||||
void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
|
||||
gd::Project &project, const gd::String &oldName, const gd::String &newName,
|
||||
bool isObjectGroup) {
|
||||
if (!isObjectGroup) { // Object groups can't be in other groups
|
||||
for (std::size_t g = 0; g < project.GetObjectGroups().size(); ++g) {
|
||||
project.GetObjectGroups()[g].RenameObject(oldName, newName);
|
||||
// Object groups can't be in other groups
|
||||
if (!isObjectGroup) {
|
||||
for (std::size_t g = 0;
|
||||
g < project.GetObjects().GetObjectGroups().size(); ++g) {
|
||||
project.GetObjects().GetObjectGroups()[g].RenameObject(oldName,
|
||||
newName);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
gd::Layout &layout = project.GetLayout(i);
|
||||
if (layout.HasObjectNamed(oldName))
|
||||
if (layout.GetObjects().HasObjectNamed(oldName))
|
||||
continue;
|
||||
|
||||
ObjectOrGroupRenamedInLayout(project, layout, oldName, newName,
|
||||
@@ -1702,55 +1810,61 @@ void WholeProjectRefactorer::GlobalObjectOrGroupRenamed(
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::GlobalObjectOrGroupRemoved(
|
||||
gd::Project &project, const gd::String &objectName, bool isObjectGroup,
|
||||
bool removeEventsAndGroups) {
|
||||
if (!isObjectGroup) { // Object groups can't be in other groups
|
||||
if (removeEventsAndGroups) {
|
||||
for (std::size_t g = 0; g < project.GetObjectGroups().size(); ++g) {
|
||||
project.GetObjectGroups()[g].RemoveObject(objectName);
|
||||
}
|
||||
}
|
||||
void WholeProjectRefactorer::GlobalObjectRemoved(
|
||||
gd::Project &project, const gd::String &objectName) {
|
||||
auto &globalGroups = project.GetObjects().GetObjectGroups();
|
||||
for (std::size_t g = 0; g < globalGroups.size(); ++g) {
|
||||
globalGroups[g].RemoveObject(objectName);
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
gd::Layout &layout = project.GetLayout(i);
|
||||
if (layout.HasObjectNamed(objectName))
|
||||
if (layout.GetObjects().HasObjectNamed(objectName))
|
||||
continue;
|
||||
|
||||
ObjectOrGroupRemovedInLayout(project, layout, objectName, isObjectGroup,
|
||||
removeEventsAndGroups);
|
||||
ObjectRemovedInLayout(project, layout, objectName);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RemoveLayer(gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
void WholeProjectRefactorer::BehaviorsAddedToGlobalObject(
|
||||
gd::Project &project, const gd::String &objectName) {
|
||||
for (std::size_t i = 0; i < project.GetLayoutsCount(); ++i) {
|
||||
gd::Layout &layout = project.GetLayout(i);
|
||||
if (layout.GetObjects().HasObjectNamed(objectName))
|
||||
continue;
|
||||
|
||||
BehaviorsAddedToObjectInLayout(project, layout, objectName);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RemoveLayerInScene(gd::Project &project,
|
||||
gd::Layout &scene,
|
||||
const gd::String &layerName) {
|
||||
if (layerName.empty())
|
||||
return;
|
||||
|
||||
layout.GetInitialInstances().RemoveAllInstancesOnLayer(layerName);
|
||||
scene.GetInitialInstances().RemoveAllInstancesOnLayer(layerName);
|
||||
|
||||
std::vector<gd::String> externalLayoutsNames =
|
||||
GetAssociatedExternalLayouts(project, layout);
|
||||
GetAssociatedExternalLayouts(project, scene);
|
||||
for (gd::String name : externalLayoutsNames) {
|
||||
auto &externalLayout = project.GetExternalLayout(name);
|
||||
externalLayout.GetInitialInstances().RemoveAllInstancesOnLayer(layerName);
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::MergeLayers(gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
void WholeProjectRefactorer::MergeLayersInScene(gd::Project &project,
|
||||
gd::Layout &scene,
|
||||
const gd::String &originLayerName,
|
||||
const gd::String &targetLayerName) {
|
||||
if (originLayerName == targetLayerName || originLayerName.empty())
|
||||
return;
|
||||
|
||||
layout.GetInitialInstances().MoveInstancesToLayer(originLayerName,
|
||||
scene.GetInitialInstances().MoveInstancesToLayer(originLayerName,
|
||||
targetLayerName);
|
||||
|
||||
std::vector<gd::String> externalLayoutsNames =
|
||||
GetAssociatedExternalLayouts(project, layout);
|
||||
GetAssociatedExternalLayouts(project, scene);
|
||||
for (gd::String name : externalLayoutsNames) {
|
||||
auto &externalLayout = project.GetExternalLayout(name);
|
||||
externalLayout.GetInitialInstances().MoveInstancesToLayer(originLayerName,
|
||||
@@ -1758,6 +1872,24 @@ void WholeProjectRefactorer::MergeLayers(gd::Project &project,
|
||||
}
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RemoveLayerInEventsBasedObject(
|
||||
gd::EventsBasedObject &eventsBasedObject, const gd::String &layerName) {
|
||||
if (layerName.empty())
|
||||
return;
|
||||
|
||||
eventsBasedObject.GetInitialInstances().RemoveAllInstancesOnLayer(layerName);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::MergeLayersInEventsBasedObject(
|
||||
gd::EventsBasedObject &eventsBasedObject, const gd::String &originLayerName,
|
||||
const gd::String &targetLayerName) {
|
||||
if (originLayerName == targetLayerName || originLayerName.empty())
|
||||
return;
|
||||
|
||||
eventsBasedObject.GetInitialInstances().MoveInstancesToLayer(originLayerName,
|
||||
targetLayerName);
|
||||
}
|
||||
|
||||
size_t WholeProjectRefactorer::GetLayoutAndExternalLayoutLayerInstancesCount(
|
||||
gd::Project &project, gd::Layout &layout, const gd::String &layerName) {
|
||||
size_t count = layout.GetInitialInstances().GetLayerInstancesCount(layerName);
|
||||
|
@@ -9,7 +9,10 @@
|
||||
#include <unordered_set>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
|
||||
namespace gd {
|
||||
class Platform;
|
||||
class Project;
|
||||
@@ -34,13 +37,27 @@ class BehaviorMetadata;
|
||||
class UnfilledRequiredBehaviorPropertyProblem;
|
||||
class ProjectBrowser;
|
||||
class SerializerElement;
|
||||
class ProjectScopedContainers;
|
||||
struct VariablesRenamingChangesetNode;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
struct VariablesChangeset {
|
||||
std::unordered_set<gd::String> removedVariableNames;
|
||||
struct VariablesRenamingChangesetNode {
|
||||
std::unordered_map<gd::String, gd::String> oldToNewVariableNames;
|
||||
std::unordered_map<gd::String, std::shared_ptr<gd::VariablesRenamingChangesetNode>>
|
||||
modifiedVariables;
|
||||
};
|
||||
|
||||
struct VariablesChangeset : VariablesRenamingChangesetNode {
|
||||
std::unordered_set<gd::String> removedVariableNames;
|
||||
|
||||
/**
|
||||
* No distinction is done between a change of the variable itself or its
|
||||
* children. Ensuring that a child is actually the one with a type change
|
||||
* would take more time than checking the instruction type is rightly set.
|
||||
*/
|
||||
std::unordered_set<gd::String> typeChangedVariableNames;
|
||||
|
||||
bool HasRemovedVariables() { return !removedVariableNames.empty(); }
|
||||
|
||||
@@ -51,8 +68,8 @@ struct VariablesChangeset {
|
||||
* \brief Tool functions to do refactoring on the whole project after
|
||||
* changes like deletion or renaming of an object.
|
||||
*
|
||||
* \TODO Ideally ObjectOrGroupRenamedInLayout, ObjectOrGroupRemovedInLayout,
|
||||
* GlobalObjectOrGroupRenamed, GlobalObjectOrGroupRemoved would be implemented
|
||||
* \TODO Ideally ObjectOrGroupRenamedInLayout, ObjectRemovedInLayout,
|
||||
* GlobalObjectOrGroupRenamed, GlobalObjectRemoved would be implemented
|
||||
* using ExposeProjectEvents.
|
||||
*/
|
||||
class GD_CORE_API WholeProjectRefactorer {
|
||||
@@ -62,7 +79,6 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
* \brief Compute the changes made on the variables of a variable container.
|
||||
*/
|
||||
static VariablesChangeset ComputeChangesetForVariablesContainer(
|
||||
gd::Project &project,
|
||||
const gd::SerializerElement &oldSerializedVariablesContainer,
|
||||
const gd::VariablesContainer &newVariablesContainer);
|
||||
|
||||
@@ -71,9 +87,9 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
* made to variables.
|
||||
*/
|
||||
static void ApplyRefactoringForVariablesContainer(
|
||||
gd::Project &project,
|
||||
const gd::VariablesContainer &newVariablesContainer,
|
||||
const gd::VariablesChangeset& changeset);
|
||||
gd::Project &project, gd::VariablesContainer &variablesContainer,
|
||||
const gd::VariablesChangeset &changeset,
|
||||
const gd::SerializerElement &originalSerializedVariables);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** an events function extension is
|
||||
@@ -376,11 +392,21 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
* This will update the layout, all external layouts associated with it
|
||||
* and all external events associated with it.
|
||||
*/
|
||||
static void ObjectOrGroupRemovedInLayout(gd::Project& project,
|
||||
static void ObjectRemovedInLayout(gd::Project& project,
|
||||
gd::Layout& layout,
|
||||
const gd::String& objectName,
|
||||
bool isObjectGroup,
|
||||
bool removeEventsAndGroups = true);
|
||||
const gd::String& objectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after behaviors are added to an object in a
|
||||
* layout.
|
||||
*
|
||||
* This will update the layout, all external events associated with it.
|
||||
* The refactor is actually applied to all objects because it allow to handle
|
||||
* groups.
|
||||
*/
|
||||
static void BehaviorsAddedToObjectInLayout(gd::Project &project,
|
||||
gd::Layout &layout,
|
||||
const gd::String &objectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after an object is removed in an events-based
|
||||
@@ -388,14 +414,10 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
*
|
||||
* This will update the events of the function and groups.
|
||||
*/
|
||||
static void ObjectOrGroupRemovedInEventsBasedObject(
|
||||
static void ObjectRemovedInEventsBasedObject(
|
||||
gd::Project& project,
|
||||
gd::EventsBasedObject& eventsBasedObject,
|
||||
gd::ObjectsContainer& globalObjectsContainer,
|
||||
gd::ObjectsContainer& objectsContainer,
|
||||
const gd::String& objectName,
|
||||
bool isObjectGroup,
|
||||
bool removeEventsAndGroups);
|
||||
const gd::String& objectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the events function after an object or group is renamed
|
||||
@@ -404,7 +426,7 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
*/
|
||||
static void ObjectOrGroupRenamedInEventsBasedObject(
|
||||
gd::Project& project,
|
||||
gd::ObjectsContainer& globalObjectsContainer,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsBasedObject& eventsBasedObject,
|
||||
const gd::String& oldName,
|
||||
const gd::String& newName,
|
||||
@@ -417,9 +439,8 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
*/
|
||||
static void ObjectOrGroupRenamedInEventsFunction(
|
||||
gd::Project& project,
|
||||
const gd::ProjectScopedContainers &projectScopedContainers,
|
||||
gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& globalObjectsContainer,
|
||||
gd::ObjectsContainer& objectsContainer,
|
||||
const gd::String& oldName,
|
||||
const gd::String& newName,
|
||||
bool isObjectGroup);
|
||||
@@ -429,14 +450,10 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
*
|
||||
* This will update the events of the function and groups.
|
||||
*/
|
||||
static void ObjectOrGroupRemovedInEventsFunction(
|
||||
static void ObjectRemovedInEventsFunction(
|
||||
gd::Project& project,
|
||||
gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& globalObjectsContainer,
|
||||
gd::ObjectsContainer& objectsContainer,
|
||||
const gd::String& objectName,
|
||||
bool isObjectGroup,
|
||||
bool removeEventsAndGroups = true);
|
||||
const gd::String& objectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after a global object is renamed.
|
||||
@@ -455,10 +472,18 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
* This will update all the layouts, all external layouts associated with them
|
||||
* and all external events used by the layouts.
|
||||
*/
|
||||
static void GlobalObjectOrGroupRemoved(gd::Project& project,
|
||||
const gd::String& objectName,
|
||||
bool isObjectGroup,
|
||||
bool removeEventsAndGroups = true);
|
||||
static void GlobalObjectRemoved(gd::Project& project,
|
||||
const gd::String& objectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after behaviors are added a global object.
|
||||
*
|
||||
* This will update all the layouts, all external events associated with them.
|
||||
* The refactor is actually applied to all objects because it allow to handle
|
||||
* groups.
|
||||
*/
|
||||
void BehaviorsAddedToGlobalObject(gd::Project &project,
|
||||
const gd::String &objectName);
|
||||
|
||||
/**
|
||||
* \brief Return the set of all the types of the objects that are using the
|
||||
@@ -489,16 +514,31 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
/**
|
||||
* \brief Remove all the instances from one layer.
|
||||
*/
|
||||
static void RemoveLayer(gd::Project &project, gd::Layout &layout,
|
||||
static void RemoveLayerInScene(gd::Project &project, gd::Layout &scene,
|
||||
const gd::String &layerName);
|
||||
|
||||
/**
|
||||
* \brief Move all the instances from one layer into another.
|
||||
*/
|
||||
static void MergeLayers(gd::Project &project, gd::Layout &layout,
|
||||
static void MergeLayersInScene(gd::Project &project, gd::Layout &scene,
|
||||
const gd::String &originLayerName,
|
||||
const gd::String &targetLayerName);
|
||||
|
||||
/**
|
||||
* \brief Remove all the instances from one layer.
|
||||
*/
|
||||
static void
|
||||
RemoveLayerInEventsBasedObject(gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &layerName);
|
||||
|
||||
/**
|
||||
* \brief Move all the instances from one layer into another.
|
||||
*/
|
||||
static void
|
||||
MergeLayersInEventsBasedObject(gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &originLayerName,
|
||||
const gd::String &targetLayerName);
|
||||
|
||||
/**
|
||||
* \brief Return the number of instances on the layer named \a layerName and
|
||||
* all its associated layouts.
|
||||
@@ -555,6 +595,13 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& behaviorName,
|
||||
std::unordered_set<gd::String>& dependentBehaviorNames);
|
||||
|
||||
static std::shared_ptr<VariablesRenamingChangesetNode>
|
||||
ComputeChangesetForVariable(const gd::Variable &oldVariable,
|
||||
const gd::Variable &newVariable);
|
||||
|
||||
static bool HasAnyVariableTypeChanged(const gd::Variable &oldVariable,
|
||||
const gd::Variable &newVariable);
|
||||
|
||||
static const gd::String behaviorObjectParameterName;
|
||||
static const gd::String parentObjectParameterName;
|
||||
|
||||
|
@@ -35,19 +35,26 @@ std::unique_ptr<gd::ObjectConfiguration> CustomObjectConfiguration::Clone() cons
|
||||
return gd::make_unique<gd::CustomObjectConfiguration>(*this);
|
||||
}
|
||||
|
||||
gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(const gd::String &objectName) {
|
||||
const gd::EventsBasedObject* CustomObjectConfiguration::GetEventsBasedObject() const {
|
||||
if (!project->HasEventsBasedObject(GetType())) {
|
||||
return nullptr;
|
||||
}
|
||||
return &project->GetEventsBasedObject(GetType());
|
||||
}
|
||||
|
||||
gd::ObjectConfiguration &CustomObjectConfiguration::GetChildObjectConfiguration(const gd::String &objectName) {
|
||||
const auto *eventsBasedObject = GetEventsBasedObject();
|
||||
if (!eventsBasedObject) {
|
||||
return badObjectConfiguration;
|
||||
}
|
||||
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
|
||||
|
||||
if (!eventsBasedObject.HasObjectNamed(objectName)) {
|
||||
if (!eventsBasedObject->GetObjects().HasObjectNamed(objectName)) {
|
||||
gd::LogError("Tried to get the configuration of a child-object:" + objectName
|
||||
+ " that doesn't exist in the event-based object: " + GetType());
|
||||
return badObjectConfiguration;
|
||||
}
|
||||
|
||||
auto &childObject = eventsBasedObject.GetObject(objectName);
|
||||
auto &childObject = eventsBasedObject->GetObjects().GetObject(objectName);
|
||||
auto configurationPosition = childObjectConfigurations.find(objectName);
|
||||
if (configurationPosition == childObjectConfigurations.end()) {
|
||||
childObjectConfigurations.insert(std::make_pair(
|
||||
@@ -90,8 +97,7 @@ bool CustomObjectConfiguration::UpdateProperty(const gd::String& propertyName,
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
CustomObjectConfiguration::GetInitialInstanceProperties(
|
||||
const gd::InitialInstance &initialInstance, gd::Project &project,
|
||||
gd::Layout &scene) {
|
||||
const gd::InitialInstance &initialInstance) {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
if (!animations.HasNoAnimations()) {
|
||||
properties["animation"] =
|
||||
@@ -105,7 +111,7 @@ CustomObjectConfiguration::GetInitialInstanceProperties(
|
||||
|
||||
bool CustomObjectConfiguration::UpdateInitialInstanceProperty(
|
||||
gd::InitialInstance &initialInstance, const gd::String &name,
|
||||
const gd::String &value, gd::Project &project, gd::Layout &scene) {
|
||||
const gd::String &value) {
|
||||
if (name == "animation") {
|
||||
initialInstance.SetRawDoubleProperty(
|
||||
"animation", std::max(0, value.empty() ? 0 : value.To<int>()));
|
||||
@@ -129,6 +135,20 @@ void CustomObjectConfiguration::DoSerializeTo(SerializerElement& element) const
|
||||
auto &childElement = childrenContentElement.AddChild(childName);
|
||||
childConfiguration->SerializeTo(childElement);
|
||||
}
|
||||
|
||||
const auto *eventsBasedObject = GetEventsBasedObject();
|
||||
if (eventsBasedObject) {
|
||||
eventsBasedObject->GetInitialInstances().SerializeTo(
|
||||
element.AddChild("instances"));
|
||||
eventsBasedObject->GetLayers().SerializeLayersTo(
|
||||
element.AddChild("layers"));
|
||||
element.SetIntAttribute("areaMinX", eventsBasedObject->GetAreaMinX());
|
||||
element.SetIntAttribute("areaMinY", eventsBasedObject->GetAreaMinY());
|
||||
element.SetIntAttribute("areaMinZ", eventsBasedObject->GetAreaMinZ());
|
||||
element.SetIntAttribute("areaMaxX", eventsBasedObject->GetAreaMaxX());
|
||||
element.SetIntAttribute("areaMaxY", eventsBasedObject->GetAreaMaxY());
|
||||
element.SetIntAttribute("areaMaxZ", eventsBasedObject->GetAreaMaxZ());
|
||||
}
|
||||
}
|
||||
void CustomObjectConfiguration::DoUnserializeFrom(Project& project,
|
||||
const SerializerElement& element) {
|
||||
@@ -198,7 +218,7 @@ void CustomObjectConfiguration::ExposeResources(gd::ArbitraryResourceWorker& wor
|
||||
}
|
||||
const auto &eventsBasedObject = project->GetEventsBasedObject(GetType());
|
||||
|
||||
for (auto& childObject : eventsBasedObject.GetObjects()) {
|
||||
for (auto& childObject : eventsBasedObject.GetObjects().GetObjects()) {
|
||||
auto &configuration = GetChildObjectConfiguration(childObject->GetName());
|
||||
configuration.ExposeResources(worker);
|
||||
}
|
||||
|
@@ -58,14 +58,10 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration {
|
||||
bool UpdateProperty(const gd::String& name, const gd::String& value) override;
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetInitialInstanceProperties(
|
||||
const gd::InitialInstance& instance,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) override;
|
||||
const gd::InitialInstance& instance) override;
|
||||
bool UpdateInitialInstanceProperty(gd::InitialInstance& instance,
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& scene) override;
|
||||
const gd::String& value) override;
|
||||
|
||||
void ExposeResources(gd::ArbitraryResourceWorker& worker) override;
|
||||
|
||||
@@ -86,6 +82,8 @@ protected:
|
||||
void DoUnserializeFrom(Project& project, const SerializerElement& element) override;
|
||||
|
||||
private:
|
||||
const gd::EventsBasedObject* GetEventsBasedObject() const;
|
||||
|
||||
const Project* project; ///< The project is used to get the
|
||||
///< EventBasedObject from the fullType.
|
||||
gd::SerializerElement objectContent;
|
||||
|
@@ -13,21 +13,19 @@ EventsBasedObject::EventsBasedObject()
|
||||
: AbstractEventsBasedEntity(
|
||||
"MyObject",
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Object),
|
||||
ObjectsContainer(),
|
||||
isRenderedIn3D(false),
|
||||
isAnimatable(false),
|
||||
isTextContainer(false) {
|
||||
isTextContainer(false),
|
||||
areaMinX(0),
|
||||
areaMinY(0),
|
||||
areaMinZ(0),
|
||||
areaMaxX(64),
|
||||
areaMaxY(64),
|
||||
areaMaxZ(64) {
|
||||
}
|
||||
|
||||
EventsBasedObject::~EventsBasedObject() {}
|
||||
|
||||
EventsBasedObject::EventsBasedObject(const gd::EventsBasedObject &_eventBasedObject)
|
||||
: AbstractEventsBasedEntity(_eventBasedObject) {
|
||||
// TODO Add a copy constructor in ObjectsContainer.
|
||||
initialObjects = gd::Clone(_eventBasedObject.initialObjects);
|
||||
objectGroups = _eventBasedObject.objectGroups;
|
||||
}
|
||||
|
||||
void EventsBasedObject::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("defaultName", defaultName);
|
||||
if (isRenderedIn3D) {
|
||||
@@ -39,10 +37,20 @@ void EventsBasedObject::SerializeTo(SerializerElement& element) const {
|
||||
if (isTextContainer) {
|
||||
element.SetBoolAttribute("isTextContainer", true);
|
||||
}
|
||||
element.SetIntAttribute("areaMinX", areaMinX);
|
||||
element.SetIntAttribute("areaMinY", areaMinY);
|
||||
element.SetIntAttribute("areaMinZ", areaMinZ);
|
||||
element.SetIntAttribute("areaMaxX", areaMaxX);
|
||||
element.SetIntAttribute("areaMaxY", areaMaxY);
|
||||
element.SetIntAttribute("areaMaxZ", areaMaxZ);
|
||||
|
||||
AbstractEventsBasedEntity::SerializeTo(element);
|
||||
SerializeObjectsTo(element.AddChild("objects"));
|
||||
SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
|
||||
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
|
||||
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
|
||||
objectsContainer.GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
|
||||
|
||||
layers.SerializeLayersTo(element.AddChild("layers"));
|
||||
initialInstances.SerializeTo(element.AddChild("instances"));
|
||||
}
|
||||
|
||||
void EventsBasedObject::UnserializeFrom(gd::Project& project,
|
||||
@@ -51,13 +59,29 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
|
||||
isRenderedIn3D = element.GetBoolAttribute("is3D", false);
|
||||
isAnimatable = element.GetBoolAttribute("isAnimatable", false);
|
||||
isTextContainer = element.GetBoolAttribute("isTextContainer", false);
|
||||
areaMinX = element.GetIntAttribute("areaMinX", 0);
|
||||
areaMinY = element.GetIntAttribute("areaMinY", 0);
|
||||
areaMinZ = element.GetIntAttribute("areaMinZ", 0);
|
||||
areaMaxX = element.GetIntAttribute("areaMaxX", 64);
|
||||
areaMaxY = element.GetIntAttribute("areaMaxY", 64);
|
||||
areaMaxZ = element.GetIntAttribute("areaMaxZ", 64);
|
||||
|
||||
AbstractEventsBasedEntity::UnserializeFrom(project, element);
|
||||
UnserializeObjectsFrom(project, element.GetChild("objects"));
|
||||
objectsContainer.UnserializeObjectsFrom(project, element.GetChild("objects"));
|
||||
if (element.HasChild("objectsFolderStructure")) {
|
||||
UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
|
||||
objectsContainer.UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
|
||||
}
|
||||
AddMissingObjectsInRootFolder();
|
||||
objectsContainer.AddMissingObjectsInRootFolder();
|
||||
objectsContainer.GetObjectGroups().UnserializeFrom(
|
||||
element.GetChild("objectsGroups"));
|
||||
|
||||
if (element.HasChild("layers")) {
|
||||
layers.UnserializeLayersFrom(element.GetChild("layers"));
|
||||
} else {
|
||||
layers.Reset();
|
||||
}
|
||||
|
||||
initialInstances.UnserializeFrom(element.GetChild("instances"));
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -3,12 +3,13 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EVENTSBASEDOBJECT_H
|
||||
#define GDCORE_EVENTSBASEDOBJECT_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "GDCore/Project/AbstractEventsBasedEntity.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/InitialInstancesContainer.h"
|
||||
#include "GDCore/Project/LayersContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
@@ -26,11 +27,10 @@ namespace gd {
|
||||
*
|
||||
* \ingroup PlatformDefinition
|
||||
*/
|
||||
class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public ObjectsContainer {
|
||||
class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
|
||||
public:
|
||||
EventsBasedObject();
|
||||
virtual ~EventsBasedObject();
|
||||
EventsBasedObject(const gd::EventsBasedObject &_eventBasedObject);
|
||||
|
||||
/**
|
||||
* \brief Return a pointer to a new EventsBasedObject constructed from
|
||||
@@ -111,6 +111,164 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
|
||||
*/
|
||||
bool IsTextContainer() const { return isTextContainer; }
|
||||
|
||||
/** \name Layers
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Get the layers of the custom object.
|
||||
*/
|
||||
const gd::LayersContainer& GetLayers() const { return layers; }
|
||||
|
||||
/**
|
||||
* \brief Get the layers of the custom object.
|
||||
*/
|
||||
gd::LayersContainer& GetLayers() { return layers; }
|
||||
///@}
|
||||
|
||||
/** \name Child objects
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Get the objects of the custom object.
|
||||
*/
|
||||
gd::ObjectsContainer& GetObjects() {
|
||||
return objectsContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the objects of the custom object.
|
||||
*/
|
||||
const gd::ObjectsContainer& GetObjects() const {
|
||||
return objectsContainer;
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Instances
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Get the instances of the custom object.
|
||||
*/
|
||||
gd::InitialInstancesContainer& GetInitialInstances() {
|
||||
return initialInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the instances of the custom object.
|
||||
*/
|
||||
const gd::InitialInstancesContainer& GetInitialInstances() const {
|
||||
return initialInstances;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the left bound of the custom object.
|
||||
*
|
||||
* This is used only if there is any initial instances.
|
||||
*
|
||||
* \see EventsBasedObject::GetInitialInstances
|
||||
*/
|
||||
int GetAreaMinX() const {
|
||||
return areaMinX;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the left bound of the custom object.
|
||||
*/
|
||||
void SetAreaMinX(int areaMinX_) {
|
||||
areaMinX = areaMinX_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the top bound of the custom object.
|
||||
*
|
||||
* This is used only if there is any initial instances.
|
||||
*
|
||||
* \see EventsBasedObject::GetInitialInstances
|
||||
*/
|
||||
int GetAreaMinY() const {
|
||||
return areaMinY;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the top bound of the custom object.
|
||||
*/
|
||||
void SetAreaMinY(int areaMinY_) {
|
||||
areaMinY = areaMinY_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the min Z bound of the custom object.
|
||||
*
|
||||
* This is used only if there is any initial instances.
|
||||
*
|
||||
* \see EventsBasedObject::GetInitialInstances
|
||||
*/
|
||||
int GetAreaMinZ() const {
|
||||
return areaMinZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the min Z bound of the custom object.
|
||||
*/
|
||||
void SetAreaMinZ(int areaMinZ_) {
|
||||
areaMinZ = areaMinZ_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the right bound of the custom object.
|
||||
*
|
||||
* This is used only if there is any initial instances.
|
||||
*
|
||||
* \see EventsBasedObject::GetInitialInstances
|
||||
*/
|
||||
int GetAreaMaxX() const {
|
||||
return areaMaxX;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the right bound of the custom object.
|
||||
*/
|
||||
void SetAreaMaxX(int areaMaxX_) {
|
||||
areaMaxX = areaMaxX_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the bottom bound of the custom object.
|
||||
*
|
||||
* This is used only if there is any initial instances.
|
||||
*
|
||||
* \see EventsBasedObject::GetInitialInstances
|
||||
*/
|
||||
int GetAreaMaxY() const {
|
||||
return areaMaxY;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the bottom bound of the custom object.
|
||||
*/
|
||||
void SetAreaMaxY(int areaMaxY_) {
|
||||
areaMaxY = areaMaxY_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the max Z bound of the custom object.
|
||||
*
|
||||
* This is used only if there is any initial instances.
|
||||
*
|
||||
* \see EventsBasedObject::GetInitialInstances
|
||||
*/
|
||||
int GetAreaMaxZ() const {
|
||||
return areaMaxZ;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the bottom bound of the custom object.
|
||||
*/
|
||||
void SetAreaMaxZ(int areaMaxZ_) {
|
||||
areaMaxZ = areaMaxZ_;
|
||||
}
|
||||
///@}
|
||||
|
||||
void SerializeTo(SerializerElement& element) const override;
|
||||
|
||||
void UnserializeFrom(gd::Project& project,
|
||||
@@ -121,8 +279,15 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity, public Ob
|
||||
bool isRenderedIn3D;
|
||||
bool isAnimatable;
|
||||
bool isTextContainer;
|
||||
gd::InitialInstancesContainer initialInstances;
|
||||
gd::LayersContainer layers;
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
double areaMinX;
|
||||
double areaMinY;
|
||||
double areaMinZ;
|
||||
double areaMaxX;
|
||||
double areaMaxY;
|
||||
double areaMaxZ;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EVENTSBASEDOBJECT_H
|
||||
|
@@ -107,6 +107,7 @@ public:
|
||||
return Insert(object, position);
|
||||
}
|
||||
void RemoveEventsFunction(const gd::String& name) { return Remove(name); }
|
||||
void ClearEventsFunctions() { return Clear(); }
|
||||
void MoveEventsFunction(std::size_t oldIndex, std::size_t newIndex) {
|
||||
return Move(oldIndex, newIndex);
|
||||
};
|
||||
|
@@ -15,7 +15,9 @@ namespace gd {
|
||||
|
||||
EventsFunctionsExtension::EventsFunctionsExtension() :
|
||||
gd::EventsFunctionsContainer(
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Extension) {}
|
||||
gd::EventsFunctionsContainer::FunctionOwner::Extension),
|
||||
globalVariables(gd::VariablesContainer::SourceType::ExtensionGlobal),
|
||||
sceneVariables(gd::VariablesContainer::SourceType::ExtensionScene) {}
|
||||
|
||||
EventsFunctionsExtension::EventsFunctionsExtension(
|
||||
const EventsFunctionsExtension& other) :
|
||||
@@ -48,6 +50,8 @@ void EventsFunctionsExtension::Init(const gd::EventsFunctionsExtension& other) {
|
||||
EventsFunctionsContainer::Init(other);
|
||||
eventsBasedBehaviors = other.eventsBasedBehaviors;
|
||||
eventsBasedObjects = other.eventsBasedObjects;
|
||||
globalVariables = other.GetGlobalVariables();
|
||||
sceneVariables = other.GetSceneVariables();
|
||||
}
|
||||
|
||||
void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
|
||||
@@ -82,6 +86,9 @@ void EventsFunctionsExtension::SerializeTo(SerializerElement& element) const {
|
||||
for (auto& dependency : dependencies)
|
||||
SerializeDependencyTo(dependency, dependenciesElement.AddChild(""));
|
||||
|
||||
GetGlobalVariables().SerializeTo(element.AddChild("globalVariables"));
|
||||
GetSceneVariables().SerializeTo(element.AddChild("sceneVariables"));
|
||||
|
||||
SerializeEventsFunctionsTo(element.AddChild("eventsFunctions"));
|
||||
eventsBasedBehaviors.SerializeElementsTo(
|
||||
"eventsBasedBehavior", element.AddChild("eventsBasedBehaviors"));
|
||||
@@ -148,6 +155,9 @@ void EventsFunctionsExtension::UnserializeExtensionDeclarationFrom(
|
||||
dependencies.push_back(
|
||||
UnserializeDependencyFrom(dependenciesElement.GetChild(i)));
|
||||
|
||||
globalVariables.UnserializeFrom(element.GetChild("globalVariables"));
|
||||
sceneVariables.UnserializeFrom(element.GetChild("sceneVariables"));
|
||||
|
||||
// Only unserialize behaviors and objects names.
|
||||
// As event based objects can contains objects using CustomBehavior and/or
|
||||
// CustomObject, this allows them to reference EventBasedBehavior and
|
||||
@@ -174,7 +184,11 @@ void EventsFunctionsExtension::UnserializeExtensionImplementationFrom(
|
||||
UnserializeEventsFunctionsFrom(project, element.GetChild("eventsFunctions"));
|
||||
eventsBasedBehaviors.UnserializeElementsFrom(
|
||||
"eventsBasedBehavior", project, element.GetChild("eventsBasedBehaviors"));
|
||||
eventsBasedObjects.UnserializeElementsFrom(
|
||||
|
||||
// It's important to load the objects without erasing them first as each object
|
||||
// might reference other objects, and so need to know if a custom object exists
|
||||
// in the project or not.
|
||||
eventsBasedObjects.ProgressivelyUnserializeElementsFrom(
|
||||
"eventsBasedObject", project, element.GetChild("eventsBasedObjects"));
|
||||
}
|
||||
|
||||
|
@@ -3,8 +3,7 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_EVENTSFUNCTIONEXTENSION_H
|
||||
#define GDCORE_EVENTSFUNCTIONEXTENSION_H
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
@@ -12,6 +11,7 @@
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/EventsFunctionsContainer.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/SerializableWithNameList.h"
|
||||
namespace gd {
|
||||
@@ -216,6 +216,41 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Variable management
|
||||
* Members functions related to layout variables management.
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Return the global variables of the extension (variables scoped to the
|
||||
* entire game lifetime).
|
||||
*/
|
||||
inline const gd::VariablesContainer& GetGlobalVariables() const {
|
||||
return globalVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the global variables of the extension (variables scoped to the
|
||||
* entire game lifetime).
|
||||
*/
|
||||
inline gd::VariablesContainer& GetGlobalVariables() { return globalVariables; }
|
||||
|
||||
/**
|
||||
* Return the global variables of the extension (variables scoped to the
|
||||
* lifetime of a scene).
|
||||
*/
|
||||
inline const gd::VariablesContainer& GetSceneVariables() const {
|
||||
return sceneVariables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the global variables of the extension (variables scoped to the
|
||||
* lifetime of a scene).
|
||||
*/
|
||||
inline gd::VariablesContainer& GetSceneVariables() { return sceneVariables; }
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Serialization
|
||||
*/
|
||||
///@{
|
||||
@@ -298,8 +333,9 @@ class GD_CORE_API EventsFunctionsExtension : public EventsFunctionsContainer {
|
||||
gd::SerializableWithNameList<EventsBasedBehavior> eventsBasedBehaviors;
|
||||
gd::SerializableWithNameList<EventsBasedObject> eventsBasedObjects;
|
||||
std::vector<gd::DependencyMetadata> dependencies;
|
||||
|
||||
gd::VariablesContainer globalVariables;
|
||||
gd::VariablesContainer sceneVariables;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EVENTSFUNCTIONEXTENSION_H
|
||||
|
@@ -9,7 +9,6 @@
|
||||
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
|
||||
#include "GDCore/Project/InitialInstancesContainer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/TinyXml/tinyxml.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
@@ -153,33 +154,35 @@ InitialInstance& InitialInstance::ResetPersistentUuid() {
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
InitialInstance::GetCustomProperties(gd::Project& project, gd::Layout& layout) {
|
||||
InitialInstance::GetCustomProperties(
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer) {
|
||||
// Find an object
|
||||
if (layout.HasObjectNamed(GetObjectName()))
|
||||
return layout.GetObject(GetObjectName())
|
||||
if (objectsContainer.HasObjectNamed(GetObjectName()))
|
||||
return objectsContainer.GetObject(GetObjectName())
|
||||
.GetConfiguration()
|
||||
.GetInitialInstanceProperties(*this, project, layout);
|
||||
else if (project.HasObjectNamed(GetObjectName()))
|
||||
return project.GetObject(GetObjectName())
|
||||
.GetInitialInstanceProperties(*this);
|
||||
else if (globalObjectsContainer.HasObjectNamed(GetObjectName()))
|
||||
return globalObjectsContainer.GetObject(GetObjectName())
|
||||
.GetConfiguration()
|
||||
.GetInitialInstanceProperties(*this, project, layout);
|
||||
.GetInitialInstanceProperties(*this);
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
||||
bool InitialInstance::UpdateCustomProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout) {
|
||||
if (layout.HasObjectNamed(GetObjectName()))
|
||||
return layout.GetObject(GetObjectName())
|
||||
bool InitialInstance::UpdateCustomProperty(
|
||||
const gd::String &name, const gd::String &value,
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer) {
|
||||
if (objectsContainer.HasObjectNamed(GetObjectName()))
|
||||
return objectsContainer.GetObject(GetObjectName())
|
||||
.GetConfiguration()
|
||||
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
|
||||
else if (project.HasObjectNamed(GetObjectName()))
|
||||
return project.GetObject(GetObjectName())
|
||||
.UpdateInitialInstanceProperty(*this, name, value);
|
||||
else if (globalObjectsContainer.HasObjectNamed(GetObjectName()))
|
||||
return globalObjectsContainer.GetObject(GetObjectName())
|
||||
.GetConfiguration()
|
||||
.UpdateInitialInstanceProperty(*this, name, value, project, layout);
|
||||
.UpdateInitialInstanceProperty(*this, name, value);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@@ -4,8 +4,8 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_INITIALINSTANCE_H
|
||||
#define GDCORE_INITIALINSTANCE_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
@@ -14,6 +14,7 @@ namespace gd {
|
||||
class PropertyDescriptor;
|
||||
class Project;
|
||||
class Layout;
|
||||
class ObjectsContainer;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -263,18 +264,18 @@ class GD_CORE_API InitialInstance {
|
||||
* \note Common properties ( name, position... ) do not need to be
|
||||
* inserted in this map
|
||||
*/
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetCustomProperties(
|
||||
gd::Project& project, gd::Layout& layout);
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
GetCustomProperties(gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer);
|
||||
|
||||
/**
|
||||
* \brief Update the property called \a name with the new \a value.
|
||||
*
|
||||
* \return false if the property could not be updated.
|
||||
*/
|
||||
bool UpdateCustomProperty(const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout);
|
||||
bool UpdateCustomProperty(const gd::String &name, const gd::String &value,
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer);
|
||||
|
||||
/**
|
||||
* \brief Get the value of a double property stored in the instance.
|
||||
@@ -361,5 +362,3 @@ class GD_CORE_API InitialInstance {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_INITIALINSTANCE_H
|
||||
|
@@ -294,17 +294,6 @@ class GD_CORE_API Layer {
|
||||
static gd::Camera badCamera;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Functor testing layer name
|
||||
*
|
||||
* \see gd::Layer
|
||||
*/
|
||||
struct LayerHasName : public std::binary_function<gd::Layer, gd::String, bool> {
|
||||
bool operator()(const Layer& layer, const gd::String& name) const {
|
||||
return layer.GetName() == name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_LAYER_H
|
||||
|
138
Core/GDCore/Project/LayersContainer.cpp
Normal file
138
Core/GDCore/Project/LayersContainer.cpp
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#include "LayersContainer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "Layer.h"
|
||||
#include "Layout.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
gd::Layer LayersContainer::badLayer;
|
||||
|
||||
LayersContainer::LayersContainer() {
|
||||
Reset();
|
||||
}
|
||||
|
||||
void LayersContainer::Reset() {
|
||||
layers.clear();
|
||||
gd::Layer layer;
|
||||
layer.SetCameraCount(1);
|
||||
layers.push_back(layer);
|
||||
}
|
||||
|
||||
gd::Layer& LayersContainer::GetLayer(const gd::String& name) {
|
||||
std::vector<gd::Layer>::iterator layer =
|
||||
find_if(layers.begin(), layers.end(), [&name](const gd::Layer& layer) {
|
||||
return layer.GetName() == name;
|
||||
});
|
||||
|
||||
if (layer != layers.end()) return *layer;
|
||||
|
||||
return badLayer;
|
||||
}
|
||||
|
||||
const gd::Layer& LayersContainer::GetLayer(const gd::String& name) const {
|
||||
std::vector<gd::Layer>::const_iterator layer =
|
||||
find_if(layers.begin(), layers.end(), [&name](const gd::Layer& layer) {
|
||||
return layer.GetName() == name;
|
||||
});
|
||||
|
||||
if (layer != layers.end()) return *layer;
|
||||
|
||||
return badLayer;
|
||||
}
|
||||
|
||||
gd::Layer& LayersContainer::GetLayer(std::size_t index) {
|
||||
return layers[index];
|
||||
}
|
||||
|
||||
const gd::Layer& LayersContainer::GetLayer(std::size_t index) const {
|
||||
return layers[index];
|
||||
}
|
||||
|
||||
std::size_t LayersContainer::GetLayersCount() const { return layers.size(); }
|
||||
|
||||
bool LayersContainer::HasLayerNamed(const gd::String& name) const {
|
||||
return (
|
||||
find_if(layers.begin(), layers.end(), [&name](const gd::Layer& layer) {
|
||||
return layer.GetName() == name;
|
||||
}) != layers.end());
|
||||
}
|
||||
std::size_t LayersContainer::GetLayerPosition(const gd::String& name) const {
|
||||
for (std::size_t i = 0; i < layers.size(); ++i) {
|
||||
if (layers[i].GetName() == name) return i;
|
||||
}
|
||||
return gd::String::npos;
|
||||
}
|
||||
|
||||
void LayersContainer::InsertNewLayer(const gd::String& name,
|
||||
std::size_t position) {
|
||||
gd::Layer newLayer;
|
||||
newLayer.SetName(name);
|
||||
if (position < layers.size())
|
||||
layers.insert(layers.begin() + position, newLayer);
|
||||
else
|
||||
layers.push_back(newLayer);
|
||||
}
|
||||
|
||||
void LayersContainer::InsertLayer(const gd::Layer& layer,
|
||||
std::size_t position) {
|
||||
if (position < layers.size())
|
||||
layers.insert(layers.begin() + position, layer);
|
||||
else
|
||||
layers.push_back(layer);
|
||||
}
|
||||
|
||||
void LayersContainer::RemoveLayer(const gd::String& name) {
|
||||
std::vector<gd::Layer>::iterator layer =
|
||||
find_if(layers.begin(), layers.end(), [&name](const gd::Layer& layer) {
|
||||
return layer.GetName() == name;
|
||||
});
|
||||
if (layer == layers.end()) return;
|
||||
|
||||
layers.erase(layer);
|
||||
}
|
||||
|
||||
void LayersContainer::SwapLayers(std::size_t firstLayerIndex,
|
||||
std::size_t secondLayerIndex) {
|
||||
if (firstLayerIndex >= layers.size() || secondLayerIndex >= layers.size())
|
||||
return;
|
||||
|
||||
std::iter_swap(layers.begin() + firstLayerIndex,
|
||||
layers.begin() + secondLayerIndex);
|
||||
}
|
||||
|
||||
void LayersContainer::MoveLayer(std::size_t oldIndex, std::size_t newIndex) {
|
||||
if (oldIndex >= layers.size() || newIndex >= layers.size()) return;
|
||||
|
||||
auto layer = layers[oldIndex];
|
||||
layers.erase(layers.begin() + oldIndex);
|
||||
InsertLayer(layer, newIndex);
|
||||
}
|
||||
|
||||
void LayersContainer::SerializeLayersTo(SerializerElement& element) const {
|
||||
element.ConsiderAsArrayOf("layer");
|
||||
for (std::size_t j = 0; j < GetLayersCount(); ++j)
|
||||
GetLayer(j).SerializeTo(element.AddChild("layer"));
|
||||
}
|
||||
|
||||
void LayersContainer::UnserializeLayersFrom(const SerializerElement& element) {
|
||||
layers.clear();
|
||||
element.ConsiderAsArrayOf("layer", "Layer");
|
||||
for (std::size_t i = 0; i < element.GetChildrenCount(); ++i) {
|
||||
gd::Layer layer;
|
||||
layer.UnserializeFrom(element.GetChild(i));
|
||||
layers.push_back(layer);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
109
Core/GDCore/Project/LayersContainer.h
Normal file
109
Core/GDCore/Project/LayersContainer.h
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/Layer.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Contains the layers for a scene or a custom object.
|
||||
*
|
||||
* \ingroup PlatformDefinition
|
||||
*/
|
||||
class GD_CORE_API LayersContainer {
|
||||
public:
|
||||
LayersContainer();
|
||||
|
||||
/**
|
||||
* \brief Return true if the layer called "name" exists.
|
||||
*/
|
||||
bool HasLayerNamed(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the layer called "name".
|
||||
*/
|
||||
Layer& GetLayer(const gd::String& name);
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the layer called "name".
|
||||
*/
|
||||
const Layer& GetLayer(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the layer at position "index" in the layers
|
||||
* list.
|
||||
*/
|
||||
Layer& GetLayer(std::size_t index);
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the layer at position "index" in the layers
|
||||
* list.
|
||||
*/
|
||||
const Layer& GetLayer(std::size_t index) const;
|
||||
|
||||
/**
|
||||
* \brief Return the position of the layer called "name" in the layers list.
|
||||
*/
|
||||
std::size_t GetLayerPosition(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* The number of layers.
|
||||
*/
|
||||
std::size_t GetLayersCount() const;
|
||||
|
||||
/**
|
||||
* Add a new empty the layer sheet called "name" at the specified
|
||||
* position in the layers list.
|
||||
*/
|
||||
void InsertNewLayer(const gd::String& name, std::size_t position);
|
||||
|
||||
/**
|
||||
* Add a new layer constructed from the layer passed as parameter.
|
||||
*
|
||||
* \param theLayer The layer that must be copied and inserted.
|
||||
* \param position Insertion position.
|
||||
*/
|
||||
void InsertLayer(const Layer& theLayer, std::size_t position);
|
||||
|
||||
/**
|
||||
* Delete the layer named "name".
|
||||
*/
|
||||
void RemoveLayer(const gd::String& name);
|
||||
|
||||
/**
|
||||
* Swap the position of the specified layers.
|
||||
*/
|
||||
void SwapLayers(std::size_t firstLayerIndex, std::size_t secondLayerIndex);
|
||||
|
||||
/**
|
||||
* Change the position of the specified layer.
|
||||
*/
|
||||
void MoveLayer(std::size_t oldIndex, std::size_t newIndex);
|
||||
|
||||
void Reset();
|
||||
|
||||
/**
|
||||
* \brief Serialize the layers.
|
||||
*/
|
||||
void SerializeLayersTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize the layers.
|
||||
*/
|
||||
void UnserializeLayersFrom(const SerializerElement& element);
|
||||
|
||||
private:
|
||||
static gd::Layer badLayer; ///< Null object, returned when GetLayer can not
|
||||
///< find an appropriate layer.
|
||||
std::vector<gd::Layer> layers; ///< Layers
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -33,7 +33,6 @@ using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
gd::Layer Layout::badLayer;
|
||||
gd::BehaviorsSharedData Layout::badBehaviorSharedData("", "");
|
||||
|
||||
Layout::Layout(const Layout& other) { Init(other); }
|
||||
@@ -53,11 +52,8 @@ Layout::Layout()
|
||||
stopSoundsOnStartup(true),
|
||||
standardSortMethod(true),
|
||||
disableInputWhenNotFocused(true),
|
||||
profiler(NULL)
|
||||
variables(gd::VariablesContainer::SourceType::Scene)
|
||||
{
|
||||
gd::Layer layer;
|
||||
layer.SetCameraCount(1);
|
||||
initialLayers.push_back(layer);
|
||||
}
|
||||
|
||||
void Layout::SetName(const gd::String& name_) {
|
||||
@@ -99,91 +95,47 @@ Layout::GetAllBehaviorSharedData() const {
|
||||
}
|
||||
|
||||
gd::Layer& Layout::GetLayer(const gd::String& name) {
|
||||
std::vector<gd::Layer>::iterator layer =
|
||||
find_if(initialLayers.begin(),
|
||||
initialLayers.end(),
|
||||
bind2nd(gd::LayerHasName(), name));
|
||||
|
||||
if (layer != initialLayers.end()) return *layer;
|
||||
|
||||
return badLayer;
|
||||
return layers.GetLayer(name);
|
||||
}
|
||||
|
||||
const gd::Layer& Layout::GetLayer(const gd::String& name) const {
|
||||
std::vector<gd::Layer>::const_iterator layer =
|
||||
find_if(initialLayers.begin(),
|
||||
initialLayers.end(),
|
||||
bind2nd(gd::LayerHasName(), name));
|
||||
|
||||
if (layer != initialLayers.end()) return *layer;
|
||||
|
||||
return badLayer;
|
||||
return layers.GetLayer(name);
|
||||
}
|
||||
|
||||
gd::Layer& Layout::GetLayer(std::size_t index) { return initialLayers[index]; }
|
||||
gd::Layer& Layout::GetLayer(std::size_t index) { return layers.GetLayer(index); }
|
||||
|
||||
const gd::Layer& Layout::GetLayer(std::size_t index) const {
|
||||
return initialLayers[index];
|
||||
return layers.GetLayer(index);
|
||||
}
|
||||
|
||||
std::size_t Layout::GetLayersCount() const { return initialLayers.size(); }
|
||||
std::size_t Layout::GetLayersCount() const { return layers.GetLayersCount(); }
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
bool Layout::HasLayerNamed(const gd::String& name) const {
|
||||
return (find_if(initialLayers.begin(),
|
||||
initialLayers.end(),
|
||||
bind2nd(gd::LayerHasName(), name)) != initialLayers.end());
|
||||
return layers.HasLayerNamed(name);
|
||||
}
|
||||
std::size_t Layout::GetLayerPosition(const gd::String& name) const {
|
||||
for (std::size_t i = 0; i < initialLayers.size(); ++i) {
|
||||
if (initialLayers[i].GetName() == name) return i;
|
||||
}
|
||||
return gd::String::npos;
|
||||
return layers.GetLayerPosition(name);
|
||||
}
|
||||
|
||||
void Layout::InsertNewLayer(const gd::String& name, std::size_t position) {
|
||||
gd::Layer newLayer;
|
||||
newLayer.SetName(name);
|
||||
if (position < initialLayers.size())
|
||||
initialLayers.insert(initialLayers.begin() + position, newLayer);
|
||||
else
|
||||
initialLayers.push_back(newLayer);
|
||||
layers.InsertNewLayer(name, position);
|
||||
}
|
||||
|
||||
void Layout::InsertLayer(const gd::Layer& layer, std::size_t position) {
|
||||
if (position < initialLayers.size())
|
||||
initialLayers.insert(initialLayers.begin() + position, layer);
|
||||
else
|
||||
initialLayers.push_back(layer);
|
||||
layers.InsertLayer(layer, position);
|
||||
}
|
||||
|
||||
void Layout::RemoveLayer(const gd::String& name) {
|
||||
std::vector<gd::Layer>::iterator layer =
|
||||
find_if(initialLayers.begin(),
|
||||
initialLayers.end(),
|
||||
bind2nd(gd::LayerHasName(), name));
|
||||
if (layer == initialLayers.end()) return;
|
||||
|
||||
initialLayers.erase(layer);
|
||||
layers.RemoveLayer(name);
|
||||
}
|
||||
|
||||
void Layout::SwapLayers(std::size_t firstLayerIndex,
|
||||
std::size_t secondLayerIndex) {
|
||||
if (firstLayerIndex >= initialLayers.size() ||
|
||||
secondLayerIndex >= initialLayers.size())
|
||||
return;
|
||||
|
||||
std::iter_swap(initialLayers.begin() + firstLayerIndex,
|
||||
initialLayers.begin() + secondLayerIndex);
|
||||
layers.SwapLayers(firstLayerIndex, secondLayerIndex);
|
||||
}
|
||||
|
||||
void Layout::MoveLayer(std::size_t oldIndex, std::size_t newIndex) {
|
||||
if (oldIndex >= initialLayers.size() || newIndex >= initialLayers.size())
|
||||
return;
|
||||
|
||||
auto layer = initialLayers[oldIndex];
|
||||
initialLayers.erase(initialLayers.begin() + oldIndex);
|
||||
InsertLayer(layer, newIndex);
|
||||
layers.MoveLayer(oldIndex, newIndex);
|
||||
}
|
||||
|
||||
void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
@@ -191,22 +143,23 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
std::vector<gd::String> allBehaviorsNames;
|
||||
|
||||
// Search in objects for the type and the name of every behaviors.
|
||||
for (std::size_t i = 0; i < initialObjects.size(); ++i) {
|
||||
for (std::size_t i = 0; i < objectsContainer.GetObjectsCount(); ++i) {
|
||||
std::vector<gd::String> objectBehaviors =
|
||||
initialObjects[i]->GetAllBehaviorNames();
|
||||
objectsContainer.GetObject(i).GetAllBehaviorNames();
|
||||
for (unsigned int j = 0; j < objectBehaviors.size(); ++j) {
|
||||
auto& behavior =
|
||||
initialObjects[i]->GetBehavior(objectBehaviors[j]);
|
||||
objectsContainer.GetObject(i).GetBehavior(objectBehaviors[j]);
|
||||
allBehaviorsTypes.push_back(behavior.GetTypeName());
|
||||
allBehaviorsNames.push_back(behavior.GetName());
|
||||
}
|
||||
}
|
||||
for (std::size_t i = 0; i < project.GetObjectsCount(); ++i) {
|
||||
auto &globalObjects = project.GetObjects();
|
||||
for (std::size_t i = 0; i < globalObjects.GetObjectsCount(); ++i) {
|
||||
std::vector<gd::String> objectBehaviors =
|
||||
project.GetObject(i).GetAllBehaviorNames();
|
||||
globalObjects.GetObject(i).GetAllBehaviorNames();
|
||||
for (std::size_t j = 0; j < objectBehaviors.size(); ++j) {
|
||||
auto& behavior =
|
||||
project.GetObject(i).GetBehavior(objectBehaviors[j]);
|
||||
globalObjects.GetObject(i).GetBehavior(objectBehaviors[j]);
|
||||
allBehaviorsTypes.push_back(behavior.GetTypeName());
|
||||
allBehaviorsNames.push_back(behavior.GetName());
|
||||
}
|
||||
@@ -290,15 +243,15 @@ void Layout::SerializeTo(SerializerElement& element) const {
|
||||
|
||||
editorSettings.SerializeTo(element.AddChild("uiSettings"));
|
||||
|
||||
GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
|
||||
objectsContainer.GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
|
||||
GetVariables().SerializeTo(element.AddChild("variables"));
|
||||
GetInitialInstances().SerializeTo(element.AddChild("instances"));
|
||||
SerializeObjectsTo(element.AddChild("objects"));
|
||||
SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
|
||||
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
|
||||
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
|
||||
SerializeLayersTo(element.AddChild("layers"));
|
||||
layers.SerializeLayersTo(element.AddChild("layers"));
|
||||
|
||||
SerializerElement& behaviorDatasElement =
|
||||
element.AddChild("behaviorsSharedData");
|
||||
@@ -316,23 +269,6 @@ void Layout::SerializeTo(SerializerElement& element) const {
|
||||
}
|
||||
}
|
||||
|
||||
void Layout::SerializeLayersTo(SerializerElement& element) const {
|
||||
element.ConsiderAsArrayOf("layer");
|
||||
for (std::size_t j = 0; j < GetLayersCount(); ++j)
|
||||
GetLayer(j).SerializeTo(element.AddChild("layer"));
|
||||
}
|
||||
#endif
|
||||
|
||||
void Layout::UnserializeLayersFrom(const SerializerElement& element) {
|
||||
initialLayers.clear();
|
||||
element.ConsiderAsArrayOf("layer", "Layer");
|
||||
for (std::size_t i = 0; i < element.GetChildrenCount(); ++i) {
|
||||
gd::Layer layer;
|
||||
layer.UnserializeFrom(element.GetChild(i));
|
||||
initialLayers.push_back(layer);
|
||||
}
|
||||
}
|
||||
|
||||
void Layout::UnserializeFrom(gd::Project& project,
|
||||
const SerializerElement& element) {
|
||||
SetBackgroundColor(element.GetIntAttribute("r"),
|
||||
@@ -348,22 +284,22 @@ void Layout::UnserializeFrom(gd::Project& project,
|
||||
editorSettings.UnserializeFrom(
|
||||
element.GetChild("uiSettings", 0, "UISettings"));
|
||||
|
||||
GetObjectGroups().UnserializeFrom(
|
||||
objectsContainer.GetObjectGroups().UnserializeFrom(
|
||||
element.GetChild("objectsGroups", 0, "GroupesObjets"));
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, GetEvents(), element.GetChild("events", 0, "Events"));
|
||||
|
||||
UnserializeObjectsFrom(project, element.GetChild("objects", 0, "Objets"));
|
||||
objectsContainer.UnserializeObjectsFrom(project, element.GetChild("objects", 0, "Objets"));
|
||||
if (element.HasChild("objectsFolderStructure")) {
|
||||
UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
|
||||
objectsContainer.UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
|
||||
}
|
||||
AddMissingObjectsInRootFolder();
|
||||
objectsContainer.AddMissingObjectsInRootFolder();
|
||||
|
||||
initialInstances.UnserializeFrom(
|
||||
element.GetChild("instances", 0, "Positions"));
|
||||
variables.UnserializeFrom(element.GetChild("variables", 0, "Variables"));
|
||||
|
||||
UnserializeLayersFrom(element.GetChild("layers", 0, "Layers"));
|
||||
layers.UnserializeLayersFrom(element.GetChild("layers", 0, "Layers"));
|
||||
|
||||
// Compatibility with GD <= 4
|
||||
gd::String deprecatedTag1 = "automatismsSharedData";
|
||||
@@ -415,10 +351,10 @@ void Layout::Init(const Layout& other) {
|
||||
stopSoundsOnStartup = other.stopSoundsOnStartup;
|
||||
disableInputWhenNotFocused = other.disableInputWhenNotFocused;
|
||||
initialInstances = other.initialInstances;
|
||||
initialLayers = other.initialLayers;
|
||||
layers = other.layers;
|
||||
variables = other.GetVariables();
|
||||
|
||||
initialObjects = gd::Clone(other.initialObjects);
|
||||
objectsContainer = other.objectsContainer;
|
||||
|
||||
behaviorsSharedData.clear();
|
||||
for (const auto& it : other.behaviorsSharedData) {
|
||||
@@ -428,9 +364,6 @@ void Layout::Init(const Layout& other) {
|
||||
|
||||
events = other.events;
|
||||
editorSettings = other.editorSettings;
|
||||
objectGroups = other.objectGroups;
|
||||
|
||||
profiler = other.profiler;
|
||||
}
|
||||
|
||||
std::vector<gd::String> GetHiddenLayers(const Layout& layout) {
|
||||
@@ -518,11 +451,13 @@ gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project,
|
||||
void GD_CORE_API FilterBehaviorNamesFromObject(
|
||||
const gd::Object &object, const gd::String &behaviorType,
|
||||
std::vector<gd::String> &behaviorNames) {
|
||||
for (size_t i = 0; i < behaviorNames.size(); i++) {
|
||||
for (size_t i = 0; i < behaviorNames.size();) {
|
||||
auto &behaviorName = behaviorNames[i];
|
||||
if (!object.HasBehaviorNamed(behaviorName) ||
|
||||
object.GetBehavior(behaviorName).GetTypeName() != behaviorType) {
|
||||
behaviorNames.erase(behaviorNames.begin() + i);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -4,20 +4,22 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_LAYOUT_H
|
||||
#define GDCORE_LAYOUT_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/EventsList.h"
|
||||
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
|
||||
#include "GDCore/Project/BehaviorsSharedData.h"
|
||||
#include "GDCore/Project/InitialInstancesContainer.h"
|
||||
#include "GDCore/Project/Layer.h"
|
||||
#include "GDCore/Project/LayersContainer.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Project/VariablesContainer.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/IDE/Dialogs/LayoutEditorCanvas/EditorSettings.h"
|
||||
|
||||
namespace gd {
|
||||
class BaseEvent;
|
||||
@@ -25,7 +27,6 @@ class Object;
|
||||
class Project;
|
||||
class InitialInstancesContainer;
|
||||
} // namespace gd
|
||||
class TiXmlElement;
|
||||
class BaseProfiler;
|
||||
#undef GetObject // Disable an annoying macro
|
||||
|
||||
@@ -36,7 +37,7 @@ namespace gd {
|
||||
*
|
||||
* \ingroup PlatformDefinition
|
||||
*/
|
||||
class GD_CORE_API Layout : public ObjectsContainer {
|
||||
class GD_CORE_API Layout {
|
||||
public:
|
||||
Layout();
|
||||
Layout(const Layout&);
|
||||
@@ -104,6 +105,24 @@ class GD_CORE_API Layout : public ObjectsContainer {
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Layout's objects
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief return the objects of the scene.
|
||||
*/
|
||||
gd::ObjectsContainer& GetObjects() {
|
||||
return objectsContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the objects of the scene.
|
||||
*/
|
||||
const gd::ObjectsContainer& GetObjects() const {
|
||||
return objectsContainer;
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Layout's initial instances
|
||||
* Members functions related to initial instances of objects created at the
|
||||
* layout start up
|
||||
@@ -147,103 +166,96 @@ class GD_CORE_API Layout : public ObjectsContainer {
|
||||
///@{
|
||||
|
||||
/**
|
||||
* Provide access to the gd::VariablesContainer member containing the layout
|
||||
* variables \see gd::VariablesContainer
|
||||
* \brief Get the variables of the scene.
|
||||
*
|
||||
* \see gd::VariablesContainer
|
||||
*/
|
||||
inline const gd::VariablesContainer& GetVariables() const {
|
||||
return variables;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide access to the gd::VariablesContainer member containing the layout
|
||||
* variables \see gd::VariablesContainer
|
||||
* \brief Get the variables of the scene.
|
||||
*
|
||||
* \see gd::VariablesContainer
|
||||
*/
|
||||
inline gd::VariablesContainer& GetVariables() { return variables; }
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Layout layers management
|
||||
* Members functions related to layout layers management.
|
||||
* TODO: This could be moved to a separate class
|
||||
/** \name Layers
|
||||
*/
|
||||
///@{
|
||||
|
||||
/**
|
||||
* \brief Return true if the layer called "name" exists.
|
||||
* \brief Get the layers of the scene.
|
||||
*/
|
||||
const gd::LayersContainer& GetLayers() const { return layers; }
|
||||
|
||||
/**
|
||||
* \brief Get the layers of the scene.
|
||||
*/
|
||||
gd::LayersContainer& GetLayers() { return layers; }
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
bool HasLayerNamed(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the layer called "name".
|
||||
* @deprecated
|
||||
*/
|
||||
Layer& GetLayer(const gd::String& name);
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the layer called "name".
|
||||
* @deprecated
|
||||
*/
|
||||
const Layer& GetLayer(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the layer at position "index" in the layers
|
||||
* list
|
||||
* @deprecated
|
||||
*/
|
||||
Layer& GetLayer(std::size_t index);
|
||||
|
||||
/**
|
||||
* \brief Return a reference to the layer at position "index" in the layers
|
||||
* list
|
||||
* @deprecated
|
||||
*/
|
||||
const Layer& GetLayer(std::size_t index) const;
|
||||
|
||||
/**
|
||||
* \brief Return the position of the layer called "name" in the layers list
|
||||
* @deprecated
|
||||
*/
|
||||
std::size_t GetLayerPosition(const gd::String& name) const;
|
||||
|
||||
/**
|
||||
* Must return the number of layers.
|
||||
* @deprecated
|
||||
*/
|
||||
std::size_t GetLayersCount() const;
|
||||
|
||||
/**
|
||||
* Must add a new empty the layer sheet called "name" at the specified
|
||||
* position in the layout list.
|
||||
* @deprecated
|
||||
*/
|
||||
void InsertNewLayer(const gd::String& name, std::size_t position);
|
||||
|
||||
/**
|
||||
* Must add a new the layer constructed from the layout passed as parameter.
|
||||
* \note No pointer or reference must be kept on the layer passed as
|
||||
* parameter. \param theLayer the layer that must be copied and inserted
|
||||
* into the project \param position Insertion position. Even if the position
|
||||
* is invalid, the layer must be inserted at the end of the layers list.
|
||||
* @deprecated
|
||||
*/
|
||||
void InsertLayer(const Layer& theLayer, std::size_t position);
|
||||
|
||||
/**
|
||||
* Must delete the layer named "name".
|
||||
* @deprecated
|
||||
*/
|
||||
void RemoveLayer(const gd::String& name);
|
||||
|
||||
/**
|
||||
* Swap the position of the specified layers.
|
||||
* @deprecated
|
||||
*/
|
||||
void SwapLayers(std::size_t firstLayerIndex, std::size_t secondLayerIndex);
|
||||
|
||||
/**
|
||||
* Change the position of the specified layer.
|
||||
* @deprecated
|
||||
*/
|
||||
void MoveLayer(std::size_t oldIndex, std::size_t newIndex);
|
||||
|
||||
/**
|
||||
* \brief Serialize the layers.
|
||||
*/
|
||||
void SerializeLayersTo(SerializerElement& element) const;
|
||||
|
||||
/**
|
||||
* \brief Unserialize the layers.
|
||||
*/
|
||||
void UnserializeLayersFrom(const SerializerElement& element);
|
||||
///@}
|
||||
|
||||
/**
|
||||
@@ -275,7 +287,8 @@ class GD_CORE_API Layout : public ObjectsContainer {
|
||||
/**
|
||||
* \brief Get the shared data stored for a behavior
|
||||
*/
|
||||
gd::BehaviorsSharedData& GetBehaviorSharedData(const gd::String& behaviorName);
|
||||
gd::BehaviorsSharedData& GetBehaviorSharedData(
|
||||
const gd::String& behaviorName);
|
||||
|
||||
/**
|
||||
* \brief Get a map of all shared data stored for behaviors
|
||||
@@ -283,7 +296,6 @@ class GD_CORE_API Layout : public ObjectsContainer {
|
||||
const std::map<gd::String, std::unique_ptr<gd::BehaviorsSharedData>>&
|
||||
GetAllBehaviorSharedData() const;
|
||||
|
||||
|
||||
/**
|
||||
* Return the settings associated to the layout.
|
||||
* \see gd::EditorSettings
|
||||
@@ -296,9 +308,7 @@ class GD_CORE_API Layout : public ObjectsContainer {
|
||||
* Return the settings associated to the layout.
|
||||
* \see gd::EditorSettings
|
||||
*/
|
||||
gd::EditorSettings& GetAssociatedEditorSettings() {
|
||||
return editorSettings;
|
||||
}
|
||||
gd::EditorSettings& GetAssociatedEditorSettings() { return editorSettings; }
|
||||
|
||||
/** \name Other properties
|
||||
*/
|
||||
@@ -339,12 +349,12 @@ class GD_CORE_API Layout : public ObjectsContainer {
|
||||
* launched
|
||||
*/
|
||||
bool StopSoundsOnStartup() const { return stopSoundsOnStartup; }
|
||||
///@}
|
||||
///@}
|
||||
|
||||
/** \name Saving and loading
|
||||
* Members functions related to saving and loading the object.
|
||||
*/
|
||||
///@{
|
||||
/** \name Saving and loading
|
||||
* Members functions related to saving and loading the object.
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief Serialize the layout.
|
||||
*/
|
||||
@@ -354,18 +364,7 @@ class GD_CORE_API Layout : public ObjectsContainer {
|
||||
* \brief Unserialize the layout.
|
||||
*/
|
||||
void UnserializeFrom(gd::Project& project, const SerializerElement& element);
|
||||
///@}
|
||||
|
||||
// TODO: GD C++ Platform specific code below
|
||||
/**
|
||||
* Get the profiler associated with the scene. Can be NULL.
|
||||
*/
|
||||
BaseProfiler* GetProfiler() const { return profiler; };
|
||||
|
||||
/**
|
||||
* Set the profiler associated with the scene. Can be NULL.
|
||||
*/
|
||||
void SetProfiler(BaseProfiler* profiler_) { profiler = profiler_; };
|
||||
///@}
|
||||
|
||||
private:
|
||||
gd::String name; ///< Scene name
|
||||
@@ -375,8 +374,9 @@ class GD_CORE_API Layout : public ObjectsContainer {
|
||||
unsigned int backgroundColorB; ///< Background color Blue component
|
||||
gd::String title; ///< Title displayed in the window
|
||||
gd::VariablesContainer variables; ///< Variables list
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
gd::InitialInstancesContainer initialInstances; ///< Initial instances
|
||||
std::vector<gd::Layer> initialLayers; ///< Initial layers
|
||||
gd::LayersContainer layers;
|
||||
std::map<gd::String, std::unique_ptr<gd::BehaviorsSharedData>>
|
||||
behaviorsSharedData; ///< Initial shared datas of behaviors
|
||||
bool stopSoundsOnStartup; ///< True to make the scene stop all sounds at
|
||||
@@ -385,20 +385,14 @@ class GD_CORE_API Layout : public ObjectsContainer {
|
||||
bool disableInputWhenNotFocused; /// If set to true, the input must be
|
||||
/// disabled when the window do not have the
|
||||
/// focus.
|
||||
static gd::Layer badLayer; ///< Null object, returned when GetLayer can not
|
||||
///< find an appropriate layer.
|
||||
static gd::BehaviorsSharedData
|
||||
badBehaviorSharedData; ///< Null object, returned when
|
||||
///< GetBehaviorSharedData can not find the
|
||||
///< specified behavior shared data.
|
||||
///< GetBehaviorSharedData can not find the
|
||||
///< specified behavior shared data.
|
||||
|
||||
EventsList events; ///< Scene events
|
||||
gd::EditorSettings editorSettings;
|
||||
|
||||
// TODO: GD C++ Platform specific code below
|
||||
|
||||
BaseProfiler* profiler; ///< Pointer to the profiler. Can be NULL.
|
||||
|
||||
/**
|
||||
* Initialize from another layout. Used by copy-ctor and assign-op.
|
||||
* Don't forget to update me if members were changed!
|
||||
@@ -445,20 +439,24 @@ gd::String GD_CORE_API GetTypeOfObject(const ObjectsContainer& game,
|
||||
bool searchInGroups = true);
|
||||
/**
|
||||
* \brief Check if an object or all objects of a group has a behavior.
|
||||
* \deprecated Use gd::ObjectsContainersList::HasBehaviorInObjectOrGroup instead.
|
||||
* \deprecated Use gd::ObjectsContainersList::HasBehaviorInObjectOrGroup
|
||||
* instead.
|
||||
*/
|
||||
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
const gd::ObjectsContainer &layout,
|
||||
const gd::String &objectOrGroupName,
|
||||
const gd::String &behaviorName,
|
||||
bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& behaviorName,
|
||||
bool searchInGroups = true);
|
||||
/**
|
||||
* \brief Get the names of behavior of a given type if an object or all objects of a group has it.
|
||||
* \brief Get the names of behavior of a given type if an object or all objects
|
||||
* of a group has it.
|
||||
*/
|
||||
std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
|
||||
const gd::ObjectsContainer &project, const gd::ObjectsContainer &layout,
|
||||
const gd::String &objectOrGroupName, const gd::String &behaviorType,
|
||||
bool searchInGroups);
|
||||
std::vector<gd::String> GD_CORE_API
|
||||
GetBehaviorNamesInObjectOrGroup(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& behaviorType,
|
||||
bool searchInGroups);
|
||||
|
||||
/**
|
||||
* \brief Check if a behavior is a default one or doesn't exist in an object or
|
||||
@@ -471,13 +469,15 @@ bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
|
||||
bool searchInGroups = true);
|
||||
|
||||
/**
|
||||
* \brief Get the type of a behavior if an object or all objects of a group has it.
|
||||
* \brief Get the type of a behavior if an object or all objects of a group has
|
||||
* it.
|
||||
*/
|
||||
gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
const gd::ObjectsContainer &layout,
|
||||
const gd::String &objectOrGroupName,
|
||||
const gd::String &behaviorName,
|
||||
bool searchInGroups = true);
|
||||
gd::String GD_CORE_API
|
||||
GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& behaviorName,
|
||||
bool searchInGroups = true);
|
||||
/**
|
||||
* \brief Get a type from a behavior name
|
||||
* @return Type of the behavior.
|
||||
@@ -504,5 +504,3 @@ GetBehaviorsOfObject(const ObjectsContainer& game,
|
||||
} // namespace gd
|
||||
|
||||
typedef gd::Layout Scene;
|
||||
|
||||
#endif // GDCORE_LAYOUT_H
|
||||
|
@@ -24,14 +24,18 @@ Object::~Object() {}
|
||||
Object::Object(const gd::String& name_,
|
||||
const gd::String& type_,
|
||||
std::unique_ptr<gd::ObjectConfiguration> configuration_)
|
||||
: name(name_), configuration(std::move(configuration_)) {
|
||||
: name(name_),
|
||||
configuration(std::move(configuration_)),
|
||||
objectVariables(gd::VariablesContainer::SourceType::Object) {
|
||||
SetType(type_);
|
||||
}
|
||||
|
||||
Object::Object(const gd::String& name_,
|
||||
const gd::String& type_,
|
||||
gd::ObjectConfiguration* configuration_)
|
||||
: name(name_), configuration(configuration_) {
|
||||
: name(name_),
|
||||
configuration(configuration_),
|
||||
objectVariables(gd::VariablesContainer::SourceType::Object) {
|
||||
SetType(type_);
|
||||
}
|
||||
|
||||
|
@@ -3,8 +3,8 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#ifndef GDCORE_OBJECT_H
|
||||
#define GDCORE_OBJECT_H
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
@@ -287,5 +287,3 @@ struct ObjectHasName : public std::binary_function<std::unique_ptr<gd::Object>,
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_OBJECT_H
|
||||
|
@@ -25,9 +25,7 @@ std::map<gd::String, gd::PropertyDescriptor> ObjectConfiguration::GetProperties(
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
ObjectConfiguration::GetInitialInstanceProperties(const gd::InitialInstance& instance,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout) {
|
||||
ObjectConfiguration::GetInitialInstanceProperties(const gd::InitialInstance& instance) {
|
||||
std::map<gd::String, gd::PropertyDescriptor> nothing;
|
||||
return nothing;
|
||||
}
|
||||
|
@@ -114,9 +114,7 @@ class GD_CORE_API ObjectConfiguration {
|
||||
* \see gd::InitialInstance
|
||||
*/
|
||||
virtual std::map<gd::String, gd::PropertyDescriptor>
|
||||
GetInitialInstanceProperties(const gd::InitialInstance& instance,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout);
|
||||
GetInitialInstanceProperties(const gd::InitialInstance& instance);
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to update a custom property of an initial
|
||||
@@ -127,9 +125,7 @@ class GD_CORE_API ObjectConfiguration {
|
||||
*/
|
||||
virtual bool UpdateInitialInstanceProperty(gd::InitialInstance& instance,
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::Project& project,
|
||||
gd::Layout& layout) {
|
||||
const gd::String& value) {
|
||||
return false;
|
||||
};
|
||||
///@}
|
||||
|
@@ -7,6 +7,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "GDCore/Tools/PolymorphicClone.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/ObjectFolderOrObject.h"
|
||||
@@ -21,6 +22,25 @@ ObjectsContainer::ObjectsContainer() {
|
||||
|
||||
ObjectsContainer::~ObjectsContainer() {}
|
||||
|
||||
ObjectsContainer::ObjectsContainer(const ObjectsContainer& other) {
|
||||
Init(other);
|
||||
}
|
||||
|
||||
ObjectsContainer& ObjectsContainer::operator=(
|
||||
const ObjectsContainer& other) {
|
||||
if (this != &other) Init(other);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void ObjectsContainer::Init(const gd::ObjectsContainer& other) {
|
||||
initialObjects = gd::Clone(other.initialObjects);
|
||||
objectGroups = other.objectGroups;
|
||||
// The objects folders are not copied.
|
||||
// It's not an issue because the UI uses the serialization for duplication.
|
||||
rootFolder = gd::make_unique<gd::ObjectFolderOrObject>("__ROOT");
|
||||
}
|
||||
|
||||
void ObjectsContainer::SerializeObjectsTo(SerializerElement& element) const {
|
||||
element.ConsiderAsArrayOf("object");
|
||||
for (std::size_t j = 0; j < initialObjects.size(); j++) {
|
||||
|
@@ -40,6 +40,9 @@ class GD_CORE_API ObjectsContainer {
|
||||
*/
|
||||
ObjectsContainer();
|
||||
virtual ~ObjectsContainer();
|
||||
|
||||
ObjectsContainer(const ObjectsContainer&);
|
||||
ObjectsContainer& operator=(const ObjectsContainer& rhs);
|
||||
|
||||
/** \name Objects management
|
||||
* Members functions related to objects management.
|
||||
@@ -230,6 +233,12 @@ class GD_CORE_API ObjectsContainer {
|
||||
|
||||
private:
|
||||
std::unique_ptr<gd::ObjectFolderOrObject> rootFolder;
|
||||
|
||||
/**
|
||||
* Initialize from another variables container, copying elements. Used by
|
||||
* copy-ctor and assign-op. Don't forget to update me if members were changed!
|
||||
*/
|
||||
void Init(const ObjectsContainer& other);
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -12,12 +12,26 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
ObjectsContainersList
|
||||
ObjectsContainersList::MakeNewEmptyObjectsContainersList() {
|
||||
ObjectsContainersList objectsContainersList;
|
||||
return objectsContainersList;
|
||||
}
|
||||
|
||||
ObjectsContainersList
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForProjectAndLayout(
|
||||
const gd::Project& project, const gd::Layout& layout) {
|
||||
ObjectsContainersList objectsContainersList;
|
||||
objectsContainersList.Add(project);
|
||||
objectsContainersList.Add(layout);
|
||||
objectsContainersList.Add(project.GetObjects());
|
||||
objectsContainersList.Add(layout.GetObjects());
|
||||
return objectsContainersList;
|
||||
}
|
||||
|
||||
ObjectsContainersList
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForProject(
|
||||
const gd::Project& project) {
|
||||
ObjectsContainersList objectsContainersList;
|
||||
objectsContainersList.Add(project.GetObjects());
|
||||
return objectsContainersList;
|
||||
}
|
||||
|
||||
@@ -31,6 +45,14 @@ ObjectsContainersList::MakeNewObjectsContainersListForContainers(
|
||||
return objectsContainersList;
|
||||
}
|
||||
|
||||
ObjectsContainersList
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
const gd::ObjectsContainer& objectsContainer) {
|
||||
ObjectsContainersList objectsContainersList;
|
||||
objectsContainersList.Add(objectsContainer);
|
||||
return objectsContainersList;
|
||||
}
|
||||
|
||||
bool ObjectsContainersList::HasObjectOrGroupNamed(
|
||||
const gd::String& name) const {
|
||||
for (auto it = objectsContainers.rbegin(); it != objectsContainers.rend();
|
||||
@@ -370,7 +392,7 @@ void ObjectsContainersList::ForEachObject(
|
||||
|
||||
gd::String ObjectsContainersList::GetTypeOfObject(
|
||||
const gd::String& objectName) const {
|
||||
if (objectsContainers.size() != 2) {
|
||||
if (objectsContainers.size() > 2) {
|
||||
std::cout << this << std::endl;
|
||||
std::cout << objectsContainers.size() << std::endl;
|
||||
// TODO: rework forwarded methods so they can work with any number of
|
||||
@@ -379,19 +401,40 @@ gd::String ObjectsContainersList::GetTypeOfObject(
|
||||
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
|
||||
"not being exactly 2. This is a logical error and will crash.");
|
||||
}
|
||||
if (objectsContainers.size() == 0) {
|
||||
gd::LogWarning("ObjectsContainersList::GetTypeOfObject called without any "
|
||||
"objectsContainer");
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
return gd::GetTypeOfObject(emptyObjectsContainer, *objectsContainers[0],
|
||||
objectName, true);
|
||||
}
|
||||
return gd::GetTypeOfObject(
|
||||
*objectsContainers[0], *objectsContainers[1], objectName, true);
|
||||
}
|
||||
|
||||
bool ObjectsContainersList::HasBehaviorInObjectOrGroup(
|
||||
const gd::String& objectOrGroupName, const gd::String& behaviorName) const {
|
||||
if (objectsContainers.size() != 2) {
|
||||
if (objectsContainers.size() > 2) {
|
||||
// TODO: rework forwarded methods so they can work with any number of
|
||||
// containers.
|
||||
gd::LogFatalError(
|
||||
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
|
||||
"ObjectsContainersList::HasBehaviorInObjectOrGroup called with objectsContainers "
|
||||
"not being exactly 2. This is a logical error and will crash.");
|
||||
}
|
||||
if (objectsContainers.size() == 0) {
|
||||
gd::LogWarning("ObjectsContainersList::HasBehaviorInObjectOrGroup called without any "
|
||||
"objectsContainer");
|
||||
return false;
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
return gd::HasBehaviorInObjectOrGroup(
|
||||
emptyObjectsContainer, *objectsContainers[0], objectOrGroupName,
|
||||
behaviorName, true);
|
||||
}
|
||||
return gd::HasBehaviorInObjectOrGroup(*objectsContainers[0],
|
||||
*objectsContainers[1],
|
||||
objectOrGroupName,
|
||||
@@ -403,13 +446,24 @@ gd::String ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup(
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& behaviorName,
|
||||
bool searchInGroups) const {
|
||||
if (objectsContainers.size() != 2) {
|
||||
if (objectsContainers.size() > 2) {
|
||||
// TODO: rework forwarded methods so they can work with any number of
|
||||
// containers.
|
||||
gd::LogFatalError(
|
||||
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
|
||||
"ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup called with objectsContainers "
|
||||
"not being exactly 2. This is a logical error and will crash.");
|
||||
}
|
||||
if (objectsContainers.size() == 0) {
|
||||
gd::LogWarning("ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup called without any "
|
||||
"objectsContainer");
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
return gd::GetTypeOfBehaviorInObjectOrGroup(
|
||||
emptyObjectsContainer, *objectsContainers[0], objectOrGroupName,
|
||||
behaviorName, searchInGroups);
|
||||
}
|
||||
return gd::GetTypeOfBehaviorInObjectOrGroup(*objectsContainers[0],
|
||||
*objectsContainers[1],
|
||||
objectOrGroupName,
|
||||
@@ -419,13 +473,23 @@ gd::String ObjectsContainersList::GetTypeOfBehaviorInObjectOrGroup(
|
||||
|
||||
gd::String ObjectsContainersList::GetTypeOfBehavior(
|
||||
const gd::String& behaviorName, bool searchInGroups) const {
|
||||
if (objectsContainers.size() != 2) {
|
||||
if (objectsContainers.size() > 2) {
|
||||
// TODO: rework forwarded methods so they can work with any number of
|
||||
// containers.
|
||||
gd::LogFatalError(
|
||||
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
|
||||
"ObjectsContainersList::GetTypeOfBehavior called with objectsContainers "
|
||||
"not being exactly 2. This is a logical error and will crash.");
|
||||
}
|
||||
if (objectsContainers.size() == 0) {
|
||||
gd::LogWarning("ObjectsContainersList::GetTypeOfBehavior called without any "
|
||||
"objectsContainer");
|
||||
return "";
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
return gd::GetTypeOfBehavior(emptyObjectsContainer, *objectsContainers[0],
|
||||
behaviorName, searchInGroups);
|
||||
}
|
||||
return gd::GetTypeOfBehavior(*objectsContainers[0],
|
||||
*objectsContainers[1],
|
||||
behaviorName,
|
||||
@@ -434,14 +498,25 @@ gd::String ObjectsContainersList::GetTypeOfBehavior(
|
||||
|
||||
std::vector<gd::String> ObjectsContainersList::GetBehaviorsOfObject(
|
||||
const gd::String& objectName, bool searchInGroups) const {
|
||||
if (objectsContainers.size() != 2) {
|
||||
if (objectsContainers.size() > 2) {
|
||||
// TODO: rework forwarded methods so they can work with any number of
|
||||
// containers.
|
||||
gd::LogFatalError(
|
||||
"ObjectsContainersList::GetTypeOfObject called with objectsContainers "
|
||||
"ObjectsContainersList::GetBehaviorsOfObject called with objectsContainers "
|
||||
"not being exactly 2. This is a logical error and will crash.");
|
||||
}
|
||||
|
||||
if (objectsContainers.size() == 0) {
|
||||
gd::LogWarning("ObjectsContainersList::GetBehaviorsOfObject called without any "
|
||||
"objectsContainer");
|
||||
std::vector<gd::String> behaviors;
|
||||
return behaviors;
|
||||
}
|
||||
if (objectsContainers.size() == 1) {
|
||||
gd::ObjectsContainer emptyObjectsContainer;
|
||||
return gd::GetBehaviorsOfObject(emptyObjectsContainer,
|
||||
*objectsContainers[0], objectName,
|
||||
searchInGroups);
|
||||
}
|
||||
return gd::GetBehaviorsOfObject(
|
||||
*objectsContainers[0], *objectsContainers[1], objectName, searchInGroups);
|
||||
}
|
||||
|
@@ -30,13 +30,21 @@ class GD_CORE_API ObjectsContainersList {
|
||||
public:
|
||||
virtual ~ObjectsContainersList(){};
|
||||
|
||||
static ObjectsContainersList MakeNewEmptyObjectsContainersList();
|
||||
|
||||
static ObjectsContainersList MakeNewObjectsContainersListForProjectAndLayout(
|
||||
const gd::Project& project, const gd::Layout& layout);
|
||||
|
||||
static ObjectsContainersList MakeNewObjectsContainersListForProject(
|
||||
const gd::Project& project);
|
||||
|
||||
static ObjectsContainersList MakeNewObjectsContainersListForContainers(
|
||||
const gd::ObjectsContainer& globalObjectsContainer,
|
||||
const gd::ObjectsContainer& objectsContainer);
|
||||
|
||||
static ObjectsContainersList MakeNewObjectsContainersListForContainer(
|
||||
const gd::ObjectsContainer& objectsContainer);
|
||||
|
||||
/**
|
||||
* \brief Check if the specified object or group exists.
|
||||
*/
|
||||
|
@@ -34,7 +34,6 @@
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/TinyXml/tinyxml.h"
|
||||
#include "GDCore/Tools/Localization.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
#include "GDCore/Tools/PolymorphicClone.h"
|
||||
@@ -75,7 +74,8 @@ Project::Project()
|
||||
currentPlatform(NULL),
|
||||
gdMajorVersion(gd::VersionWrapper::Major()),
|
||||
gdMinorVersion(gd::VersionWrapper::Minor()),
|
||||
gdBuildVersion(gd::VersionWrapper::Build()) {}
|
||||
gdBuildVersion(gd::VersionWrapper::Build()),
|
||||
variables(gd::VariablesContainer::SourceType::Global) {}
|
||||
|
||||
Project::~Project() {}
|
||||
|
||||
@@ -834,15 +834,15 @@ void Project::UnserializeFrom(const SerializerElement& element) {
|
||||
*this, eventsFunctionsExtensionElement);
|
||||
}
|
||||
|
||||
GetObjectGroups().UnserializeFrom(
|
||||
objectsContainer.GetObjectGroups().UnserializeFrom(
|
||||
element.GetChild("objectsGroups", 0, "ObjectGroups"));
|
||||
resourcesManager.UnserializeFrom(
|
||||
element.GetChild("resources", 0, "Resources"));
|
||||
UnserializeObjectsFrom(*this, element.GetChild("objects", 0, "Objects"));
|
||||
objectsContainer.UnserializeObjectsFrom(*this, element.GetChild("objects", 0, "Objects"));
|
||||
if (element.HasChild("objectsFolderStructure")) {
|
||||
UnserializeFoldersFrom(*this, element.GetChild("objectsFolderStructure", 0));
|
||||
objectsContainer.UnserializeFoldersFrom(*this, element.GetChild("objectsFolderStructure", 0));
|
||||
}
|
||||
AddMissingObjectsInRootFolder();
|
||||
objectsContainer.AddMissingObjectsInRootFolder();
|
||||
|
||||
GetVariables().UnserializeFrom(element.GetChild("variables", 0, "Variables"));
|
||||
|
||||
@@ -994,9 +994,9 @@ void Project::SerializeTo(SerializerElement& element) const {
|
||||
std::cout << "ERROR: The project current platform is NULL.";
|
||||
|
||||
resourcesManager.SerializeTo(element.AddChild("resources"));
|
||||
SerializeObjectsTo(element.AddChild("objects"));
|
||||
SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
|
||||
GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
|
||||
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
|
||||
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
|
||||
objectsContainer.GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
|
||||
GetVariables().SerializeTo(element.AddChild("variables"));
|
||||
|
||||
element.SetAttribute("firstLayout", firstLayout);
|
||||
@@ -1163,7 +1163,6 @@ void Project::Init(const gd::Project& game) {
|
||||
platformSpecificAssets = game.platformSpecificAssets;
|
||||
loadingScreen = game.loadingScreen;
|
||||
watermark = game.watermark;
|
||||
objectGroups = game.objectGroups;
|
||||
|
||||
extensionProperties = game.extensionProperties;
|
||||
|
||||
@@ -1176,7 +1175,7 @@ void Project::Init(const gd::Project& game) {
|
||||
|
||||
resourcesManager = game.resourcesManager;
|
||||
|
||||
initialObjects = gd::Clone(game.initialObjects);
|
||||
objectsContainer = game.objectsContainer;
|
||||
|
||||
scenes = gd::Clone(game.scenes);
|
||||
|
||||
|
@@ -4,11 +4,12 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_PROJECT_H
|
||||
#define GDCORE_PROJECT_H
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Events/CodeGeneration/DiagnosticReport.h"
|
||||
#include "GDCore/Project/ExtensionProperties.h"
|
||||
#include "GDCore/Project/LoadingScreen.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
@@ -47,7 +48,7 @@ namespace gd {
|
||||
*
|
||||
* \ingroup PlatformDefinition
|
||||
*/
|
||||
class GD_CORE_API Project : public ObjectsContainer {
|
||||
class GD_CORE_API Project {
|
||||
public:
|
||||
Project();
|
||||
Project(const Project&);
|
||||
@@ -983,6 +984,24 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
|
||||
///@}
|
||||
|
||||
/** \name Global objects
|
||||
*/
|
||||
///@{
|
||||
/**
|
||||
* \brief return the objects of the project.
|
||||
*/
|
||||
gd::ObjectsContainer& GetObjects() {
|
||||
return objectsContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the objects of the project.
|
||||
*/
|
||||
const gd::ObjectsContainer& GetObjects() const {
|
||||
return objectsContainer;
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Identifier names
|
||||
*/
|
||||
///@{
|
||||
@@ -1050,6 +1069,10 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
std::size_t position = -1);
|
||||
///@}
|
||||
|
||||
gd::WholeProjectDiagnosticReport& GetWholeProjectDiagnosticReport() {
|
||||
return wholeProjectDiagnosticReport;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialize from another game. Used by copy-ctor and assign-op.
|
||||
@@ -1085,6 +1108,7 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
///< startup.
|
||||
std::vector<std::unique_ptr<gd::Layout> > scenes; ///< List of all scenes
|
||||
gd::VariablesContainer variables; ///< Initial global variables
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
std::vector<std::unique_ptr<gd::ExternalLayout> >
|
||||
externalLayouts; ///< List of all externals layouts
|
||||
std::vector<std::unique_ptr<gd::EventsFunctionsExtension> >
|
||||
@@ -1125,6 +1149,7 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
externalEvents; ///< List of all externals events
|
||||
ExtensionProperties
|
||||
extensionProperties; ///< The properties of the extensions.
|
||||
gd::WholeProjectDiagnosticReport wholeProjectDiagnosticReport;
|
||||
mutable unsigned int gdMajorVersion; ///< The GD major version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdMinorVersion; ///< The GD minor version used the last
|
||||
@@ -1134,5 +1159,3 @@ class GD_CORE_API Project : public ObjectsContainer {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_PROJECT_H
|
||||
|
148
Core/GDCore/Project/ProjectScopedContainers.cpp
Normal file
148
Core/GDCore/Project/ProjectScopedContainers.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "ProjectScopedContainers.h"
|
||||
|
||||
#include "GDCore/IDE/EventsFunctionTools.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/ObjectsContainer.h"
|
||||
#include "GDCore/Events/Event.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForEventsFunctionsExtension(
|
||||
const gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension) {
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewEmptyObjectsContainersList(),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
};
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
const gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer ¶meterObjectsContainer) {
|
||||
|
||||
gd::EventsFunctionTools::FreeEventsFunctionToObjectsContainer(
|
||||
project, eventsFunctionsExtension, eventsFunction, parameterObjectsContainer);
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddParameters(
|
||||
eventsFunction.GetParametersForEvents(eventsFunctionsExtension));
|
||||
|
||||
return projectScopedContainers;
|
||||
};
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
const gd::Project &project, const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer ¶meterObjectsContainer) {
|
||||
|
||||
gd::EventsFunctionTools::BehaviorEventsFunctionToObjectsContainer(
|
||||
project,
|
||||
eventsBasedBehavior,
|
||||
eventsFunction,
|
||||
parameterObjectsContainer);
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(eventsFunctionsExtension),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
eventsBasedBehavior.GetSharedPropertyDescriptors());
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
eventsBasedBehavior.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction.GetParametersForEvents(
|
||||
eventsBasedBehavior.GetEventsFunctions()));
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer ¶meterObjectsContainer) {
|
||||
|
||||
gd::EventsFunctionTools::ObjectEventsFunctionToObjectsContainer(
|
||||
project, eventsBasedObject, eventsFunction, parameterObjectsContainer);
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
parameterObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(
|
||||
eventsFunctionsExtension),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
eventsBasedObject.GetPropertyDescriptors());
|
||||
projectScopedContainers.AddParameters(eventsFunction.GetParametersForEvents(
|
||||
eventsBasedObject.GetEventsFunctions()));
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersForEventsBasedObject(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ObjectsContainer &outputObjectsContainer) {
|
||||
|
||||
outputObjectsContainer.GetObjects().clear();
|
||||
outputObjectsContainer.GetObjectGroups().Clear();
|
||||
outputObjectsContainer.InsertNewObject(
|
||||
project,
|
||||
gd::PlatformExtension::GetObjectFullType(
|
||||
eventsFunctionsExtension.GetName(), eventsBasedObject.GetName()),
|
||||
"Object", outputObjectsContainer.GetObjectsCount());
|
||||
gd::EventsFunctionTools::CopyEventsBasedObjectChildrenToObjectsContainer(
|
||||
eventsBasedObject, outputObjectsContainer);
|
||||
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForContainer(
|
||||
outputObjectsContainer),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(
|
||||
eventsFunctionsExtension),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
projectScopedContainers.AddPropertiesContainer(
|
||||
eventsBasedObject.GetPropertyDescriptors());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
ProjectScopedContainers
|
||||
ProjectScopedContainers::MakeNewProjectScopedContainersWithLocalVariables(
|
||||
const ProjectScopedContainers &projectScopedContainers,
|
||||
const gd::BaseEvent &event) {
|
||||
ProjectScopedContainers newProjectScopedContainers = projectScopedContainers;
|
||||
newProjectScopedContainers.variablesContainersList =
|
||||
VariablesContainersList::MakeNewVariablesContainersListPushing(
|
||||
projectScopedContainers.GetVariablesContainersList(),
|
||||
event.GetVariables());
|
||||
return newProjectScopedContainers;
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -13,6 +13,11 @@ class ObjectsContainersList;
|
||||
class VariablesContainersList;
|
||||
class PropertiesContainersList;
|
||||
class NamedPropertyDescriptor;
|
||||
class BaseEvent;
|
||||
class EventsFunctionsExtension;
|
||||
class EventsFunction;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -51,6 +56,21 @@ class ProjectScopedContainers {
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForProject(const gd::Project &project) {
|
||||
ProjectScopedContainers projectScopedContainers(
|
||||
ObjectsContainersList::MakeNewObjectsContainersListForProject(
|
||||
project),
|
||||
VariablesContainersList::
|
||||
MakeNewVariablesContainersListForProject(project),
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use another method for an explicit context instead.
|
||||
*/
|
||||
static ProjectScopedContainers MakeNewProjectScopedContainersFor(
|
||||
const gd::ObjectsContainer &globalObjectsContainers,
|
||||
const gd::ObjectsContainer &objectsContainers) {
|
||||
@@ -61,7 +81,47 @@ class ProjectScopedContainers {
|
||||
PropertiesContainersList::MakeNewEmptyPropertiesContainersList());
|
||||
|
||||
return projectScopedContainers;
|
||||
}
|
||||
};
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForEventsFunctionsExtension(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForFreeEventsFunction(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsFunction& eventsFunction,
|
||||
gd::ObjectsContainer& parameterObjectsContainer);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForBehaviorEventsFunction(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer ¶meterObjectsContainer);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForObjectEventsFunction(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::EventsFunction &eventsFunction,
|
||||
gd::ObjectsContainer ¶meterObjectsContainer);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersForEventsBasedObject(
|
||||
const gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
gd::ObjectsContainer &outputObjectsContainer);
|
||||
|
||||
static ProjectScopedContainers
|
||||
MakeNewProjectScopedContainersWithLocalVariables(
|
||||
const ProjectScopedContainers &projectScopedContainers,
|
||||
const gd::BaseEvent &event);
|
||||
|
||||
ProjectScopedContainers &AddPropertiesContainer(
|
||||
const gd::PropertiesContainer &container) {
|
||||
@@ -152,6 +212,14 @@ class ProjectScopedContainers {
|
||||
return variablesContainersList;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Allow modification of the variables containers list. This is used
|
||||
* by code generation which does push and pop of local variable containers.
|
||||
*/
|
||||
gd::VariablesContainersList &GetVariablesContainersList() {
|
||||
return variablesContainersList;
|
||||
};
|
||||
|
||||
const gd::PropertiesContainersList &GetPropertiesContainersList() const {
|
||||
return propertiesContainersList;
|
||||
};
|
||||
|
@@ -198,7 +198,24 @@ void Variable::MoveChildInArray(const size_t oldIndex, const size_t newIndex) {
|
||||
childrenArray.insert(childrenArray.begin() + newIndex, std::move(object));
|
||||
}
|
||||
|
||||
Variable& Variable::PushNew() { return GetAtIndex(GetChildrenCount()); };
|
||||
Variable& Variable::PushNew() {
|
||||
const size_t count = GetChildrenCount();
|
||||
auto& variable = GetAtIndex(count);
|
||||
if (type == Type::Array && count > 0) {
|
||||
const auto childType = GetAtIndex(count - 1).type;
|
||||
variable.type = childType;
|
||||
if (childType == Type::Number) {
|
||||
variable.SetValue(0);
|
||||
}
|
||||
else if (childType == Type::String) {
|
||||
variable.SetString("");
|
||||
}
|
||||
else if (childType == Type::Boolean) {
|
||||
variable.SetBool(false);
|
||||
}
|
||||
}
|
||||
return variable;
|
||||
};
|
||||
|
||||
void Variable::RemoveAtIndex(const size_t index) {
|
||||
if (index >= childrenArray.size()) return;
|
||||
@@ -300,6 +317,23 @@ void Variable::UnserializeFrom(const SerializerElement& element) {
|
||||
|
||||
Variable& Variable::ResetPersistentUuid() {
|
||||
persistentUuid = UUID::MakeUuid4();
|
||||
for (auto& it : children) {
|
||||
it.second->ResetPersistentUuid();
|
||||
}
|
||||
for (auto& it : childrenArray) {
|
||||
it->ResetPersistentUuid();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Variable& Variable::ClearPersistentUuid() {
|
||||
persistentUuid = "";
|
||||
for (auto& it : children) {
|
||||
it.second->ClearPersistentUuid();
|
||||
}
|
||||
for (auto& it : childrenArray) {
|
||||
it->ClearPersistentUuid();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@@ -30,6 +30,8 @@ class GD_CORE_API Variable {
|
||||
public:
|
||||
static gd::Variable badVariable;
|
||||
enum Type {
|
||||
Unknown,
|
||||
|
||||
// Primitive types
|
||||
String,
|
||||
Number,
|
||||
@@ -349,7 +351,7 @@ class GD_CORE_API Variable {
|
||||
* \brief Remove the persistent UUID - when the variable no
|
||||
* longer needs to be recognized between serializations.
|
||||
*/
|
||||
Variable& ClearPersistentUuid() { persistentUuid = ""; return *this; };
|
||||
Variable& ClearPersistentUuid();
|
||||
|
||||
/**
|
||||
* \brief Get the persistent UUID used to recognize
|
||||
|
@@ -11,7 +11,6 @@
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/TinyXml/tinyxml.h"
|
||||
#include "GDCore/Tools/UUID/UUID.h"
|
||||
|
||||
namespace gd {
|
||||
@@ -35,7 +34,13 @@ class VariableHasName {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
VariablesContainer::VariablesContainer() {}
|
||||
VariablesContainer::VariablesContainer()
|
||||
: sourceType(VariablesContainer::SourceType::Unknown) {}
|
||||
|
||||
VariablesContainer::VariablesContainer(
|
||||
VariablesContainer::SourceType sourceType_) {
|
||||
sourceType = sourceType_;
|
||||
}
|
||||
|
||||
bool VariablesContainer::Has(const gd::String& name) const {
|
||||
auto i =
|
||||
@@ -229,6 +234,7 @@ VariablesContainer& VariablesContainer::operator=(
|
||||
}
|
||||
|
||||
void VariablesContainer::Init(const gd::VariablesContainer& other) {
|
||||
sourceType = other.sourceType;
|
||||
persistentUuid = other.persistentUuid;
|
||||
variables.clear();
|
||||
for (auto& it : other.variables) {
|
||||
|
@@ -4,8 +4,7 @@
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
#ifndef GDCORE_VARIABLESCONTAINER_H
|
||||
#define GDCORE_VARIABLESCONTAINER_H
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "GDCore/Project/Variable.h"
|
||||
@@ -13,7 +12,6 @@
|
||||
namespace gd {
|
||||
class SerializerElement;
|
||||
}
|
||||
class TiXmlElement;
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -29,12 +27,25 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API VariablesContainer {
|
||||
public:
|
||||
enum SourceType {
|
||||
Unknown,
|
||||
Global,
|
||||
Scene,
|
||||
Object,
|
||||
Local,
|
||||
ExtensionGlobal,
|
||||
ExtensionScene
|
||||
};
|
||||
|
||||
VariablesContainer();
|
||||
VariablesContainer(const SourceType sourceType);
|
||||
VariablesContainer(const VariablesContainer&);
|
||||
virtual ~VariablesContainer(){};
|
||||
|
||||
VariablesContainer& operator=(const VariablesContainer& rhs);
|
||||
|
||||
SourceType GetSourceType() const { return sourceType; }
|
||||
|
||||
/** \name Variables management
|
||||
* Members functions related to variables management.
|
||||
*/
|
||||
@@ -89,7 +100,6 @@ class GD_CORE_API VariablesContainer {
|
||||
*/
|
||||
const gd::String& GetNameAt(std::size_t index) const;
|
||||
|
||||
#if defined(GD_IDE_ONLY)
|
||||
/**
|
||||
* \brief return the position of the variable called "name" in the variable
|
||||
* list
|
||||
@@ -131,7 +141,6 @@ class GD_CORE_API VariablesContainer {
|
||||
* \brief Move the specified variable at a new position in the list.
|
||||
*/
|
||||
void Move(std::size_t oldIndex, std::size_t newIndex);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Clear all variables of the container.
|
||||
@@ -178,6 +187,7 @@ class GD_CORE_API VariablesContainer {
|
||||
///@}
|
||||
|
||||
private:
|
||||
SourceType sourceType;
|
||||
std::vector<std::pair<gd::String, std::shared_ptr<gd::Variable>>> variables;
|
||||
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID,
|
||||
///< useful for computing changesets.
|
||||
@@ -192,5 +202,3 @@ class GD_CORE_API VariablesContainer {
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_VARIABLESCONTAINER_H
|
||||
|
@@ -5,20 +5,50 @@
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/Variable.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
Variable VariablesContainersList::badVariable;
|
||||
VariablesContainer VariablesContainersList::badVariablesContainer;
|
||||
|
||||
VariablesContainersList
|
||||
VariablesContainersList::MakeNewVariablesContainersListForProjectAndLayout(
|
||||
const gd::Project& project, const gd::Layout& layout) {
|
||||
VariablesContainersList variablesContainersList;
|
||||
variablesContainersList.Add(project.GetVariables());
|
||||
variablesContainersList.Add(layout.GetVariables());
|
||||
variablesContainersList.Push(project.GetVariables());
|
||||
variablesContainersList.Push(layout.GetVariables());
|
||||
variablesContainersList.firstLocalVariableContainerIndex = 2;
|
||||
return variablesContainersList;
|
||||
}
|
||||
|
||||
VariablesContainersList
|
||||
VariablesContainersList::MakeNewVariablesContainersListForProject(
|
||||
const gd::Project& project) {
|
||||
VariablesContainersList variablesContainersList;
|
||||
variablesContainersList.Push(project.GetVariables());
|
||||
variablesContainersList.firstLocalVariableContainerIndex = 1;
|
||||
return variablesContainersList;
|
||||
}
|
||||
|
||||
VariablesContainersList
|
||||
VariablesContainersList::MakeNewVariablesContainersListForEventsFunctionsExtension(
|
||||
const gd::EventsFunctionsExtension &extension) {
|
||||
VariablesContainersList variablesContainersList;
|
||||
variablesContainersList.Push(extension.GetGlobalVariables());
|
||||
variablesContainersList.Push(extension.GetSceneVariables());
|
||||
variablesContainersList.firstLocalVariableContainerIndex = 2;
|
||||
return variablesContainersList;
|
||||
}
|
||||
|
||||
VariablesContainersList
|
||||
VariablesContainersList::MakeNewVariablesContainersListPushing(
|
||||
const VariablesContainersList& variablesContainersList, const gd::VariablesContainer& variablesContainer) {
|
||||
VariablesContainersList newVariablesContainersList(variablesContainersList);
|
||||
newVariablesContainersList.Push(variablesContainer);
|
||||
return newVariablesContainersList;
|
||||
}
|
||||
|
||||
VariablesContainersList
|
||||
VariablesContainersList::MakeNewEmptyVariablesContainersList() {
|
||||
VariablesContainersList variablesContainersList;
|
||||
@@ -43,6 +73,37 @@ const Variable& VariablesContainersList::Get(const gd::String& name) const {
|
||||
return badVariable;
|
||||
}
|
||||
|
||||
const VariablesContainer &
|
||||
VariablesContainersList::GetVariablesContainerFromVariableName(
|
||||
const gd::String &variableName) const {
|
||||
for (auto it = variablesContainers.rbegin(); it != variablesContainers.rend();
|
||||
++it) {
|
||||
if ((*it)->Has(variableName))
|
||||
return **it;
|
||||
}
|
||||
return badVariablesContainer;
|
||||
}
|
||||
|
||||
std::size_t
|
||||
VariablesContainersList::GetVariablesContainerPositionFromVariableName(
|
||||
const gd::String &variableName) const {
|
||||
for (std::size_t i = variablesContainers.size() - 1; i >= 0 ; --i) {
|
||||
if (variablesContainers[i]->Has(variableName))
|
||||
return i;
|
||||
}
|
||||
return gd::String::npos;
|
||||
}
|
||||
|
||||
std::size_t VariablesContainersList::GetLocalVariablesContainerPosition(
|
||||
const gd::VariablesContainer &localVariableContainer) const {
|
||||
for (std::size_t i = firstLocalVariableContainerIndex;
|
||||
i < variablesContainers.size(); ++i) {
|
||||
if (variablesContainers[i] == &localVariableContainer)
|
||||
return i - firstLocalVariableContainerIndex;
|
||||
}
|
||||
return gd::String::npos;
|
||||
}
|
||||
|
||||
bool VariablesContainersList::HasVariablesContainer(const gd::VariablesContainer& variablesContainer) const {
|
||||
for (auto it = variablesContainers.rbegin(); it != variablesContainers.rend();
|
||||
++it) {
|
||||
|
@@ -8,6 +8,7 @@ class Project;
|
||||
class Layout;
|
||||
class VariablesContainer;
|
||||
class Variable;
|
||||
class EventsFunctionsExtension;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
@@ -30,6 +31,20 @@ class GD_CORE_API VariablesContainersList {
|
||||
MakeNewVariablesContainersListForProjectAndLayout(const gd::Project& project,
|
||||
const gd::Layout& layout);
|
||||
|
||||
static VariablesContainersList
|
||||
MakeNewVariablesContainersListForProject(const gd::Project& project);
|
||||
|
||||
static VariablesContainersList
|
||||
MakeNewVariablesContainersListForEventsFunctionsExtension(
|
||||
const gd::EventsFunctionsExtension &extension);
|
||||
|
||||
static VariablesContainersList MakeNewVariablesContainersListPushing(
|
||||
const VariablesContainersList &variablesContainersList,
|
||||
const gd::VariablesContainer &variablesContainer);
|
||||
|
||||
/**
|
||||
* @deprecated Use another method for an explicit context instead.
|
||||
*/
|
||||
static VariablesContainersList MakeNewEmptyVariablesContainersList();
|
||||
|
||||
/**
|
||||
@@ -47,6 +62,10 @@ class GD_CORE_API VariablesContainersList {
|
||||
*/
|
||||
bool HasVariablesContainer(const gd::VariablesContainer& variablesContainer) const;
|
||||
|
||||
// TODO: Rename GetTopMostVariablesContainer and GetBottomMostVariablesContainer
|
||||
// to give a clearer access to segments of the container list.
|
||||
// For instance, a project tree segment and an event tree segment.
|
||||
|
||||
/**
|
||||
* Get the variables container at the top of the scope (so the most "global" one).
|
||||
* \brief Avoid using apart when a scope must be forced.
|
||||
@@ -57,29 +76,76 @@ class GD_CORE_API VariablesContainersList {
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the variables container at the bottom of the scope (so the most "local" one).
|
||||
* Get the variables container at the bottom of the scope
|
||||
* (so the most "local" one) excluding local variables.
|
||||
* \brief Avoid using apart when a scope must be forced.
|
||||
*/
|
||||
const VariablesContainer* GetBottomMostVariablesContainer() const {
|
||||
if (variablesContainers.empty()) return nullptr;
|
||||
return variablesContainers.back();
|
||||
return variablesContainers.at(firstLocalVariableContainerIndex - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the variables container for a given variable.
|
||||
*/
|
||||
const VariablesContainer &
|
||||
GetVariablesContainerFromVariableName(const gd::String &variableName) const;
|
||||
|
||||
/**
|
||||
* Get the variables container index for a given variable.
|
||||
*/
|
||||
std::size_t GetVariablesContainerPositionFromVariableName(
|
||||
const gd::String &variableName) const;
|
||||
|
||||
/**
|
||||
* \brief Get the index of the given local variables container.
|
||||
*/
|
||||
std::size_t GetLocalVariablesContainerPosition(
|
||||
const gd::VariablesContainer &localVariableContainer) const;
|
||||
|
||||
/**
|
||||
* \brief Get the variable container at the specified index in the list.
|
||||
*
|
||||
* \warning Trying to access to a not existing variable container will result
|
||||
* in undefined behavior.
|
||||
*/
|
||||
const gd::VariablesContainer& GetVariablesContainer(std::size_t index) const {
|
||||
return *variablesContainers.at(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the number variable containers.
|
||||
*/
|
||||
std::size_t GetVariablesContainersCount() const { return variablesContainers.size(); }
|
||||
|
||||
/**
|
||||
* \brief Call the callback for each variable having a name matching the specified search.
|
||||
*/
|
||||
void ForEachVariableMatchingSearch(const gd::String& search, std::function<void(const gd::String& name, const gd::Variable& variable)> fn) const;
|
||||
|
||||
/** Do not use - should be private but accessible to let Emscripten create a temporary. */
|
||||
VariablesContainersList() {};
|
||||
private:
|
||||
|
||||
void Add(const gd::VariablesContainer& variablesContainer) {
|
||||
/**
|
||||
* \brief Push a new variables container to the context.
|
||||
*/
|
||||
void Push(const gd::VariablesContainer& variablesContainer) {
|
||||
variablesContainers.push_back(&variablesContainer);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Pop a variables container from the context.
|
||||
*/
|
||||
void Pop() {
|
||||
variablesContainers.pop_back();
|
||||
};
|
||||
|
||||
|
||||
/** Do not use - should be private but accessible to let Emscripten create a temporary. */
|
||||
VariablesContainersList(): firstLocalVariableContainerIndex(0) {};
|
||||
private:
|
||||
|
||||
std::vector<const gd::VariablesContainer*> variablesContainers;
|
||||
std::size_t firstLocalVariableContainerIndex;
|
||||
static Variable badVariable;
|
||||
static VariablesContainer badVariablesContainer;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -17,91 +17,11 @@
|
||||
#include "rapidjson/document.h"
|
||||
#include "rapidjson/prettywriter.h"
|
||||
#include "rapidjson/rapidjson.h"
|
||||
#if !defined(EMSCRIPTEN)
|
||||
#include "GDCore/TinyXml/tinyxml.h"
|
||||
#endif
|
||||
|
||||
using namespace rapidjson;
|
||||
|
||||
namespace gd {
|
||||
|
||||
#if !defined(EMSCRIPTEN)
|
||||
void Serializer::ToXML(SerializerElement& element, TiXmlElement* xmlElement) {
|
||||
if (!xmlElement) return;
|
||||
|
||||
if (element.IsValueUndefined()) {
|
||||
const std::map<gd::String, SerializerValue>& attributes =
|
||||
element.GetAllAttributes();
|
||||
for (std::map<gd::String, SerializerValue>::const_iterator it =
|
||||
attributes.begin();
|
||||
it != attributes.end();
|
||||
++it) {
|
||||
const SerializerValue& attr = it->second;
|
||||
|
||||
if (attr.IsBoolean())
|
||||
xmlElement->SetAttribute(it->first.c_str(),
|
||||
attr.GetBool() ? "true" : "false");
|
||||
else if (attr.IsString())
|
||||
xmlElement->SetAttribute(it->first.c_str(), attr.GetString().c_str());
|
||||
else if (attr.IsInt())
|
||||
xmlElement->SetAttribute(it->first.c_str(), attr.GetInt());
|
||||
else if (attr.IsDouble())
|
||||
xmlElement->SetDoubleAttribute(it->first.c_str(), attr.GetDouble());
|
||||
else
|
||||
xmlElement->SetAttribute(it->first.c_str(), attr.GetString().c_str());
|
||||
}
|
||||
|
||||
const std::vector<
|
||||
std::pair<gd::String, std::shared_ptr<SerializerElement> > >& children =
|
||||
element.GetAllChildren();
|
||||
for (size_t i = 0; i < children.size(); ++i) {
|
||||
if (children[i].second == std::shared_ptr<SerializerElement>()) continue;
|
||||
|
||||
TiXmlElement* xmlChild = new TiXmlElement(children[i].first.c_str());
|
||||
xmlElement->LinkEndChild(xmlChild);
|
||||
ToXML(*children[i].second, xmlChild);
|
||||
}
|
||||
} else {
|
||||
TiXmlText* xmlValue = new TiXmlText(element.GetValue().GetString().c_str());
|
||||
xmlElement->LinkEndChild(xmlValue);
|
||||
}
|
||||
}
|
||||
|
||||
void Serializer::FromXML(SerializerElement& element,
|
||||
const TiXmlElement* xmlElement) {
|
||||
if (!xmlElement) return;
|
||||
|
||||
const TiXmlAttribute* attr = xmlElement->FirstAttribute();
|
||||
while (attr) {
|
||||
if (attr->Name() != NULL) {
|
||||
gd::String name = gd::String::FromUTF8(attr->Name()).ReplaceInvalid();
|
||||
if (attr->Value())
|
||||
element.SetAttribute(
|
||||
name, gd::String::FromUTF8(attr->Value()).ReplaceInvalid());
|
||||
}
|
||||
|
||||
attr = attr->Next();
|
||||
}
|
||||
|
||||
const TiXmlElement* child = xmlElement->FirstChildElement();
|
||||
while (child) {
|
||||
if (child->Value()) {
|
||||
gd::String name = gd::String::FromUTF8(child->Value()).ReplaceInvalid();
|
||||
SerializerElement& childElement = element.AddChild(name);
|
||||
FromXML(childElement, child);
|
||||
}
|
||||
|
||||
child = child->NextSiblingElement();
|
||||
}
|
||||
|
||||
if (xmlElement->GetText()) {
|
||||
SerializerValue value;
|
||||
value.Set(gd::String::FromUTF8(xmlElement->GetText()).ReplaceInvalid());
|
||||
element.SetValue(value);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
gd::String Serializer::ToEscapedXMLString(const gd::String& str) {
|
||||
return str.FindAndReplace("&", "&")
|
||||
.FindAndReplace("'", "'")
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user