mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
101 Commits
v5.4.211
...
infra/circ
Author | SHA1 | Date | |
---|---|---|---|
![]() |
a054cfc456 | ||
![]() |
7fef706d9a | ||
![]() |
8bd6797909 | ||
![]() |
58ba2668c2 | ||
![]() |
b34e802dcb | ||
![]() |
31dac9cc93 | ||
![]() |
ab97258832 | ||
![]() |
2ece223737 | ||
![]() |
8342873b6e | ||
![]() |
0a85fd3814 | ||
![]() |
fe15b6d30b | ||
![]() |
f3c3559518 | ||
![]() |
9f10bf45ad | ||
![]() |
a403b1343b | ||
![]() |
83dba6c21e | ||
![]() |
7a4aea6557 | ||
![]() |
82a6abacb4 | ||
![]() |
f60613cc64 | ||
![]() |
274aedb3d9 | ||
![]() |
efb31c3caf | ||
![]() |
6781c0fd6e | ||
![]() |
e9781133e1 | ||
![]() |
8972e0e3a6 | ||
![]() |
4c76a5979b | ||
![]() |
484a0daec4 | ||
![]() |
de432c1bf2 | ||
![]() |
8c7dcc1c23 | ||
![]() |
39648af248 | ||
![]() |
5c7bbf5293 | ||
![]() |
9d97b9d0eb | ||
![]() |
b39b12864f | ||
![]() |
2c3dbbbbde | ||
![]() |
72cc60bae9 | ||
![]() |
c03e94849b | ||
![]() |
80daaf5e5b | ||
![]() |
cb457cfd04 | ||
![]() |
0a55aa631b | ||
![]() |
8e104f9ae4 | ||
![]() |
a90b9a27e9 | ||
![]() |
6321e82f63 | ||
![]() |
05fc63ab1b | ||
![]() |
85a6a21934 | ||
![]() |
a9741e7b42 | ||
![]() |
23afe7b71c | ||
![]() |
85757e6d98 | ||
![]() |
524ca4dbb3 | ||
![]() |
55cf710ef5 | ||
![]() |
eee7e7f04c | ||
![]() |
ecd984e08b | ||
![]() |
d0a7fbbd02 | ||
![]() |
2a2c930b74 | ||
![]() |
f6cb203029 | ||
![]() |
fe743bbe57 | ||
![]() |
78c31408d4 | ||
![]() |
75a038344a | ||
![]() |
f0567b674c | ||
![]() |
9b85f35856 | ||
![]() |
f4568febf2 | ||
![]() |
de7f60b693 | ||
![]() |
3a595b200e | ||
![]() |
431b5929e8 | ||
![]() |
ec2e82cee5 | ||
![]() |
76517f1a2a | ||
![]() |
43f5bd1c0e | ||
![]() |
7198a22ae2 | ||
![]() |
46c52905f6 | ||
![]() |
40954bf497 | ||
![]() |
02c06ac6e7 | ||
![]() |
1fa3f59a77 | ||
![]() |
cc371273ce | ||
![]() |
364ec2ecfb | ||
![]() |
0d36a27b87 | ||
![]() |
6d597a430b | ||
![]() |
27b71b08e5 | ||
![]() |
82158f7073 | ||
![]() |
8ba352d4ba | ||
![]() |
6cda5d08be | ||
![]() |
1a3a27b73b | ||
![]() |
96d912a6f2 | ||
![]() |
ed3acd5f0d | ||
![]() |
3f269206d1 | ||
![]() |
76b5aefdbc | ||
![]() |
9ef7af803c | ||
![]() |
c77f9b9e0c | ||
![]() |
035ddb8a7a | ||
![]() |
e7dac1bafc | ||
![]() |
54f00e7c57 | ||
![]() |
0bf9dae2b0 | ||
![]() |
428aac8ab0 | ||
![]() |
9391fc2841 | ||
![]() |
cea34337c6 | ||
![]() |
dc45f3dae5 | ||
![]() |
0ca26a865e | ||
![]() |
1bce13f326 | ||
![]() |
34f8f5750a | ||
![]() |
3b9a612094 | ||
![]() |
3a84ed7c89 | ||
![]() |
ef604fd442 | ||
![]() |
d88dc4772f | ||
![]() |
02d40a1d52 | ||
![]() |
35082825d4 |
@@ -13,6 +13,7 @@ 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)
|
||||
win: circleci/windows@5.0.0
|
||||
jobs:
|
||||
# Build the **entire** app for macOS.
|
||||
build-macos:
|
||||
@@ -174,8 +175,58 @@ jobs:
|
||||
name: Deploy to S3 (latest)
|
||||
command: aws s3 sync newIDE/electron-app/dist s3://gdevelop-releases/$(git rev-parse --abbrev-ref HEAD)/latest/
|
||||
|
||||
# Build the **entire** app for Windows.
|
||||
build-windows:
|
||||
executor:
|
||||
name: win/default
|
||||
size: xlarge
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- run:
|
||||
name: Install Node.js
|
||||
command: nvm install 20; nvm use 20
|
||||
|
||||
# TODO: Build GDevelop.js?
|
||||
|
||||
- restore_cache:
|
||||
keys:
|
||||
- gd-win-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}-{{ checksum "GDevelop.js/package.json" }}
|
||||
# fallback to using the latest cache if no exact match is found
|
||||
- gd-win-nodejs-dependencies---
|
||||
|
||||
# GDevelop IDE dependencies.
|
||||
- run:
|
||||
name: Install GDevelop IDE dependencies (1)
|
||||
command: nvm use 20; npm -v; cd newIDE\app; npm install; cd ..\electron-app; npm install
|
||||
|
||||
- save_cache:
|
||||
paths:
|
||||
- newIDE/electron-app/node_modules
|
||||
- newIDE/app/node_modules
|
||||
- GDevelop.js/node_modules
|
||||
key: gd-win-nodejs-dependencies-{{ checksum "newIDE/app/package.json" }}-{{ checksum "newIDE/electron-app/package.json" }}-{{ checksum "GDevelop.js/package.json" }}
|
||||
|
||||
- run:
|
||||
name: Build the NSIS executable
|
||||
command: cd newIDE\electron-app; node scripts/build.js --win nsis --publish=never
|
||||
- run:
|
||||
name: Build the AppX
|
||||
command: cd newIDE\electron-app; node scripts/build.js --skip-app-build --win appx --publish=never
|
||||
- run:
|
||||
name: Clean artifacts
|
||||
command: Remove-Item -Path "newIDE\electron-app\dist\win-unpacked" -Recurse -Force
|
||||
|
||||
# Upload artifacts (CircleCI)
|
||||
- store_artifacts:
|
||||
path: newIDE/electron-app/dist
|
||||
|
||||
# Upload artifacts (AWS)
|
||||
# TODO
|
||||
|
||||
# Build the WebAssembly library only (so that it's cached on a S3 and easy to re-use).
|
||||
build-gdevelop_js-wasm-only:
|
||||
resource_class: medium+ # Compilation time decrease linearly with the number of CPUs, but not linking (so "large" does not speedup total build time).
|
||||
docker:
|
||||
- image: cimg/node:16.13
|
||||
|
||||
@@ -232,10 +283,84 @@ jobs:
|
||||
name: Deploy to S3 (latest)
|
||||
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/latest/
|
||||
|
||||
# Build the WebAssembly library with clang-tidy and memory sanitizers.
|
||||
build-gdevelop_js-debug-sanitizers-and-extra-checks:
|
||||
resource_class: xlarge # Total time decrease linearly with the number of CPUs.
|
||||
docker:
|
||||
- image: cimg/node:16.13
|
||||
|
||||
working_directory: ~/GDevelop
|
||||
|
||||
steps:
|
||||
- checkout
|
||||
- aws-cli/setup
|
||||
|
||||
# System dependencies (for Emscripten)
|
||||
- run:
|
||||
name: Install dependencies for Emscripten
|
||||
command: sudo apt-get update && sudo apt install cmake
|
||||
|
||||
- run:
|
||||
name: Install dependencies for clang-tidy v19
|
||||
command: wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && sudo ./llvm.sh 19 && sudo apt install clang-tidy-19
|
||||
|
||||
- run:
|
||||
name: Install Python3 dependencies for Emscripten
|
||||
command: sudo apt install python-is-python3 python3-distutils -y
|
||||
|
||||
- run:
|
||||
name: Install Emscripten (for GDevelop.js)
|
||||
command: git clone https://github.com/juj/emsdk.git && cd emsdk && ./emsdk install 3.1.21 && ./emsdk activate 3.1.21 && cd ..
|
||||
|
||||
# GDevelop.js dependencies
|
||||
- restore_cache:
|
||||
keys:
|
||||
- gdevelop.js-linux-nodejs-dependencies-{{ checksum "GDevelop.js/package-lock.json" }}
|
||||
# fallback to using the latest cache if no exact match is found
|
||||
- gdevelop.js-linux-nodejs-dependencies-
|
||||
|
||||
- run:
|
||||
name: Install GDevelop.js dependencies and build it
|
||||
command: cd GDevelop.js && npm install && cd ..
|
||||
|
||||
# Build GDevelop.js
|
||||
- run:
|
||||
name: Build GDevelop.js ('debug-sanitizers' variant)
|
||||
command: cd GDevelop.js && source ../emsdk/emsdk_env.sh && npm run build -- --variant=debug-sanitizers
|
||||
|
||||
- run:
|
||||
name: Run clang-tidy
|
||||
command: cd GDevelop.js && npm run lint
|
||||
|
||||
- run:
|
||||
name: Run tests
|
||||
command: cd GDevelop.js && npm run test -- --maxWorkers=4
|
||||
|
||||
# Upload artifacts (CircleCI)
|
||||
- store_artifacts:
|
||||
path: Binaries/embuild/GDevelop.js
|
||||
|
||||
# Upload artifacts (AWS)
|
||||
- run:
|
||||
name: Deploy to S3 (specific commit)
|
||||
command: aws s3 sync Binaries/embuild/GDevelop.js s3://gdevelop-gdevelop.js/$(git rev-parse --abbrev-ref HEAD)/variant/debug-sanitizers/commit/$(git rev-parse HEAD)/
|
||||
|
||||
workflows:
|
||||
builds:
|
||||
gdevelop_js-wasm:
|
||||
jobs:
|
||||
- build-gdevelop_js-wasm-only
|
||||
gdevelop_js-wasm-extra-checks:
|
||||
jobs:
|
||||
- build-gdevelop_js-debug-sanitizers-and-extra-checks:
|
||||
# Extra checks are resource intensive so don't all run them.
|
||||
filters:
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- /experimental-build.*/
|
||||
builds:
|
||||
jobs:
|
||||
- build-windows #TODO: filter by branch once it's verified to work.
|
||||
- build-macos:
|
||||
filters:
|
||||
branches:
|
||||
|
4
.clang-tidy
Normal file
4
.clang-tidy
Normal file
@@ -0,0 +1,4 @@
|
||||
Checks: 'clang-diagnostic-*,clang-analyzer-*,cppcoreguidelines-*,-cppcoreguidelines-explicit-virtual-functions,-cppcoreguidelines-avoid-const-or-ref-data-members,-cppcoreguidelines-special-member-functions,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-non-private-member-variables-in-classes,-cppcoreguidelines-owning-memory,-cppcoreguidelines-virtual-class-destructor,-clang-analyzer-optin.performance.Padding,-cppcoreguidelines-narrowing-conversions'
|
||||
WarningsAsErrors: 'cppcoreguidelines-pro-type-member-init, clang-analyzer-optin.cplusplus.UninitializedObject'
|
||||
HeaderFilterRegex: '.*'
|
||||
FormatStyle: none
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -114,7 +114,8 @@
|
||||
"__bits": "cpp",
|
||||
"__verbose_abort": "cpp",
|
||||
"variant": "cpp",
|
||||
"charconv": "cpp"
|
||||
"charconv": "cpp",
|
||||
"execution": "cpp"
|
||||
},
|
||||
"files.exclude": {
|
||||
"Binaries/*build*": true,
|
||||
|
@@ -60,7 +60,7 @@ if("${CMAKE_BUILD_TYPE}" STREQUAL "Release" AND NOT WIN32 AND CMAKE_COMPILER_IS_
|
||||
endif()
|
||||
|
||||
#Activate C++11
|
||||
set(CMAKE_CXX_STANDARD 11) # Upgrading to C++17 would need to remove usage of bind2nd (should be easy).
|
||||
set(CMAKE_CXX_STANDARD 11) # Upgrading to C++17 should be tried.
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
|
||||
# Mark some warnings as errors
|
||||
@@ -69,12 +69,18 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
# uninitialized variables or other hard to debug bugs.
|
||||
add_compile_options(
|
||||
-Wall
|
||||
-Wextra
|
||||
-Wuninitialized
|
||||
-Wconditional-uninitialized
|
||||
-Wno-unknown-warning-option
|
||||
-Wno-reorder-ctor
|
||||
-Wno-reorder
|
||||
-Wno-unused-parameter
|
||||
-Wno-pessimizing-move
|
||||
-Wno-unused-variable
|
||||
-Wno-unused-variable # Not a good style, but not a risk
|
||||
-Wno-unused-private-field
|
||||
-Wno-ignored-qualifiers # Not a risk
|
||||
-Wno-sign-compare # Not a big risk
|
||||
|
||||
# Make as much warnings considered as errors as possible (only one for now).
|
||||
-Werror=return-stack-address
|
||||
|
@@ -72,8 +72,6 @@ class GD_CORE_API WhileEvent : public gd::BaseEvent {
|
||||
///< de/activate infinite loop warning when the
|
||||
///< user create the event
|
||||
|
||||
mutable unsigned int whileConditionsHeight;
|
||||
|
||||
int GetConditionsHeight() const;
|
||||
int GetActionsHeight() const;
|
||||
int GetWhileConditionsHeight() const;
|
||||
|
@@ -14,10 +14,10 @@
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API ProjectDiagnostic {
|
||||
public:
|
||||
public:
|
||||
enum ErrorType {
|
||||
UndeclaredVariable,
|
||||
MissingBehavior,
|
||||
@@ -25,12 +25,17 @@ public:
|
||||
MismatchedObjectType,
|
||||
};
|
||||
|
||||
ProjectDiagnostic(ErrorType type_, const gd::String &message_,
|
||||
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(){};
|
||||
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; }
|
||||
@@ -38,7 +43,7 @@ public:
|
||||
const gd::String &GetActualValue() const { return actualValue; }
|
||||
const gd::String &GetExpectedValue() const { return expectedValue; }
|
||||
|
||||
private:
|
||||
private:
|
||||
ErrorType type;
|
||||
gd::String message;
|
||||
gd::String objectName;
|
||||
@@ -47,12 +52,12 @@ private:
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API DiagnosticReport {
|
||||
public:
|
||||
DiagnosticReport(){};
|
||||
virtual ~DiagnosticReport(){};
|
||||
public:
|
||||
DiagnosticReport() {};
|
||||
virtual ~DiagnosticReport() {};
|
||||
|
||||
void Add(const gd::ProjectDiagnostic &projectDiagnostic) {
|
||||
projectDiagnostics.push_back(
|
||||
@@ -67,32 +72,39 @@ public:
|
||||
|
||||
const gd::String &GetSceneName() const { return sceneName; }
|
||||
|
||||
void SetSceneName(const gd::String &sceneName_) {
|
||||
sceneName = sceneName_;
|
||||
void SetSceneName(const gd::String &sceneName_) { sceneName = sceneName_; }
|
||||
|
||||
void LogAllDiagnostics() {
|
||||
for (auto &diagnostic : projectDiagnostics) {
|
||||
std::cout << diagnostic->GetMessage()
|
||||
<< "(object: " << diagnostic->GetObjectName()
|
||||
<< ", actual value: " << diagnostic->GetActualValue()
|
||||
<< ", expected value: " << diagnostic->GetExpectedValue() << ")"
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::vector<std::unique_ptr<gd::ProjectDiagnostic>> projectDiagnostics;
|
||||
gd::String sceneName;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief
|
||||
* \brief
|
||||
*/
|
||||
class GD_CORE_API WholeProjectDiagnosticReport {
|
||||
public:
|
||||
WholeProjectDiagnosticReport(){};
|
||||
virtual ~WholeProjectDiagnosticReport(){};
|
||||
public:
|
||||
WholeProjectDiagnosticReport() {};
|
||||
virtual ~WholeProjectDiagnosticReport() {};
|
||||
|
||||
const DiagnosticReport &Get(std::size_t index) const {
|
||||
return *diagnosticReports[index].get();
|
||||
};
|
||||
|
||||
void Clear() {
|
||||
diagnosticReports.clear();
|
||||
};
|
||||
void Clear() { diagnosticReports.clear(); };
|
||||
|
||||
DiagnosticReport& AddNewDiagnosticReportForScene(const gd::String &sceneName) {
|
||||
DiagnosticReport &AddNewDiagnosticReportForScene(
|
||||
const gd::String &sceneName) {
|
||||
auto diagnosticReport = gd::make_unique<gd::DiagnosticReport>();
|
||||
diagnosticReport->SetSceneName(sceneName);
|
||||
diagnosticReports.push_back(std::move(diagnosticReport));
|
||||
@@ -102,7 +114,7 @@ public:
|
||||
std::size_t Count() const { return diagnosticReports.size(); };
|
||||
|
||||
bool HasAnyIssue() {
|
||||
for (auto& diagnosticReport : diagnosticReports) {
|
||||
for (auto &diagnosticReport : diagnosticReports) {
|
||||
if (diagnosticReport->Count() > 0) {
|
||||
return true;
|
||||
}
|
||||
@@ -110,8 +122,8 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
private:
|
||||
std::vector<std::unique_ptr<gd::DiagnosticReport>> diagnosticReports;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
} // namespace gd
|
||||
|
@@ -345,14 +345,14 @@ gd::String EventsCodeGenerator::GenerateConditionCode(
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
|
||||
objectInParameter, "");
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!expectedObjectType.empty() &&
|
||||
actualObjectType != expectedObjectType) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
|
||||
actualObjectType, expectedObjectType, objectInParameter);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
@@ -509,7 +509,7 @@ void EventsCodeGenerator::CheckBehaviorParameters(
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MissingBehavior, "",
|
||||
actualBehaviorType, expectedBehaviorType, lastObjectName);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -567,14 +567,14 @@ gd::String EventsCodeGenerator::GenerateActionCode(
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::UnknownObject, "",
|
||||
objectInParameter, "");
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Unknown object - skipped. */";
|
||||
} else if (!expectedObjectType.empty() &&
|
||||
actualObjectType != expectedObjectType) {
|
||||
gd::ProjectDiagnostic projectDiagnostic(
|
||||
gd::ProjectDiagnostic::ErrorType::MismatchedObjectType, "",
|
||||
actualObjectType, expectedObjectType, objectInParameter);
|
||||
diagnosticReport->Add(projectDiagnostic);
|
||||
if (diagnosticReport) diagnosticReport->Add(projectDiagnostic);
|
||||
return "/* Mismatched object type - skipped. */";
|
||||
}
|
||||
}
|
||||
|
@@ -36,8 +36,8 @@ struct GD_CORE_API ExpressionParserLocation {
|
||||
|
||||
private:
|
||||
bool isValid;
|
||||
size_t startPosition;
|
||||
size_t endPosition;
|
||||
size_t startPosition = 0;
|
||||
size_t endPosition = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@@ -1768,6 +1768,22 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsBaseObjectExtension(
|
||||
.AddParameter("expression",
|
||||
_("Angle of tolerance, in degrees (0: minimum tolerance)"))
|
||||
.AddCodeOnlyParameter("conditionInverted", "")
|
||||
.SetHidden()
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
.AddCondition("IsTurnedTowardObject",
|
||||
_("An object is turned toward another"),
|
||||
_("Check if an object is turned toward another"),
|
||||
_("_PARAM0_ is turned toward _PARAM1_ ± _PARAM2_°"),
|
||||
_("Angle"),
|
||||
"res/conditions/estTourne24.png",
|
||||
"res/conditions/estTourne.png")
|
||||
.AddParameter("objectList", _("Name of the object"))
|
||||
.AddParameter("objectList", _("Name of the second object"))
|
||||
.AddParameter("expression",
|
||||
_("Angle of tolerance, in degrees (0: minimum tolerance)"))
|
||||
.AddCodeOnlyParameter("conditionInverted", "")
|
||||
.MarkAsAdvanced();
|
||||
|
||||
extension
|
||||
|
@@ -33,6 +33,7 @@ void GD_CORE_API BuiltinExtensionsImplementer::ImplementsSpriteExtension(
|
||||
"most elements of a game."),
|
||||
"CppPlatform/Extensions/spriteicon.png")
|
||||
.SetCategoryFullName(_("General"))
|
||||
.SetOpenFullEditorLabel(_("Edit animations"))
|
||||
.AddDefaultBehavior("EffectCapability::EffectBehavior")
|
||||
.AddDefaultBehavior("ResizableCapability::ResizableBehavior")
|
||||
.AddDefaultBehavior("ScalableCapability::ScalableBehavior")
|
||||
|
@@ -47,19 +47,11 @@ void SpriteObject::DoSerializeTo(gd::SerializerElement& element) const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> SpriteObject::GetProperties()
|
||||
const {
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
properties[_("Animate even if hidden or far from the screen")]
|
||||
.SetValue(updateIfNotVisible ? "true" : "false")
|
||||
.SetType("Boolean");
|
||||
properties["PLEASE_ALSO_SHOW_EDIT_BUTTON_THANKS"].SetValue("");
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
bool SpriteObject::UpdateProperty(const gd::String& name,
|
||||
const gd::String& value) {
|
||||
if (name == _("Animate even if hidden or far from the screen"))
|
||||
updateIfNotVisible = value == "1";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -37,8 +37,7 @@ BehaviorMetadata::BehaviorMetadata(
|
||||
className(className_),
|
||||
iconFilename(icon24x24),
|
||||
instance(instance_),
|
||||
sharedDatasInstance(sharedDatasInstance_),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {
|
||||
sharedDatasInstance(sharedDatasInstance_) {
|
||||
SetFullName(gd::String(fullname_));
|
||||
SetDescription(gd::String(description_));
|
||||
SetDefaultName(gd::String(defaultName_));
|
||||
@@ -441,12 +440,18 @@ std::map<gd::String, gd::PropertyDescriptor> BehaviorMetadata::GetSharedProperti
|
||||
|
||||
const std::vector<gd::String>& BehaviorMetadata::GetRequiredBehaviorTypes() const {
|
||||
requiredBehaviors.clear();
|
||||
for (auto& property : Get().GetProperties()) {
|
||||
if (!instance) {
|
||||
return requiredBehaviors;
|
||||
}
|
||||
for (auto& property : instance->GetProperties()) {
|
||||
const String& propertyName = property.first;
|
||||
const gd::PropertyDescriptor& propertyDescriptor = property.second;
|
||||
|
||||
if (propertyDescriptor.GetType() == "Behavior") {
|
||||
requiredBehaviors.push_back(propertyDescriptor.GetExtraInfo()[0]);
|
||||
const auto& extraInfos = propertyDescriptor.GetExtraInfo();
|
||||
if (extraInfos.size() > 0) {
|
||||
requiredBehaviors.push_back(extraInfos[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return requiredBehaviors;
|
||||
|
@@ -307,6 +307,15 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
return *this;
|
||||
}
|
||||
|
||||
BehaviorMetadata &SetOpenFullEditorLabel(const gd::String& label) {
|
||||
openFullEditorLabel = label;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gd::String& GetOpenFullEditorLabel() const {
|
||||
return openFullEditorLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the associated gd::Behavior, handling behavior contents.
|
||||
*
|
||||
@@ -384,7 +393,8 @@ class GD_CORE_API BehaviorMetadata : public InstructionOrExpressionContainerMeta
|
||||
mutable std::vector<gd::String> requiredBehaviors;
|
||||
bool isPrivate = false;
|
||||
bool isHidden = false;
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
gd::String openFullEditorLabel;
|
||||
QuickCustomization::Visibility quickCustomizationVisibility = QuickCustomization::Visibility::Default;
|
||||
|
||||
// TODO: Nitpicking: convert these to std::unique_ptr to clarify ownership.
|
||||
std::shared_ptr<gd::Behavior> instance;
|
||||
|
@@ -185,10 +185,10 @@ class GD_CORE_API EffectMetadata {
|
||||
gd::String fullname;
|
||||
gd::String description;
|
||||
std::vector<gd::String> includeFiles;
|
||||
bool isMarkedAsNotWorkingForObjects;
|
||||
bool isMarkedAsOnlyWorkingFor2D;
|
||||
bool isMarkedAsOnlyWorkingFor3D;
|
||||
bool isMarkedAsUnique;
|
||||
bool isMarkedAsNotWorkingForObjects = false;
|
||||
bool isMarkedAsOnlyWorkingFor2D = false;
|
||||
bool isMarkedAsOnlyWorkingFor3D = false;
|
||||
bool isMarkedAsUnique = false;
|
||||
std::map<gd::String, gd::PropertyDescriptor> properties;
|
||||
};
|
||||
|
||||
|
@@ -19,7 +19,8 @@ EventMetadata::EventMetadata(const gd::String &name_,
|
||||
: fullname(fullname_),
|
||||
description(description_),
|
||||
group(group_),
|
||||
instance(instance_) {
|
||||
instance(instance_),
|
||||
hasCustomCodeGenerator(false) {
|
||||
ClearCodeGenerationAndPreprocessing();
|
||||
if (instance) instance->SetType(name_);
|
||||
}
|
||||
|
@@ -83,7 +83,7 @@ class GD_CORE_API EventMetadata {
|
||||
gd::String group;
|
||||
|
||||
std::shared_ptr<gd::BaseEvent> instance;
|
||||
bool hasCustomCodeGenerator;
|
||||
bool hasCustomCodeGenerator = false;
|
||||
std::function<gd::String(gd::BaseEvent& event,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& context)>
|
||||
|
@@ -288,8 +288,8 @@ class GD_CORE_API MetadataProvider {
|
||||
static EffectMetadata badEffectMetadata;
|
||||
static gd::InstructionMetadata badInstructionMetadata;
|
||||
static gd::ExpressionMetadata badExpressionMetadata;
|
||||
int useless; // Useless member to avoid emscripten "must have a positive
|
||||
// integer typeid pointer" runtime error.
|
||||
int useless = 0; // Useless member to avoid emscripten "must have a positive
|
||||
// integer typeid pointer" runtime error.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -323,6 +323,15 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
*/
|
||||
bool IsRenderedIn3D() const { return isRenderedIn3D; }
|
||||
|
||||
ObjectMetadata &SetOpenFullEditorLabel(const gd::String& label) {
|
||||
openFullEditorLabel = label;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const gd::String& GetOpenFullEditorLabel() const {
|
||||
return openFullEditorLabel;
|
||||
}
|
||||
|
||||
std::map<gd::String, gd::InstructionMetadata> conditionsInfos;
|
||||
std::map<gd::String, gd::InstructionMetadata> actionsInfos;
|
||||
std::map<gd::String, gd::ExpressionMetadata> expressionsInfos;
|
||||
@@ -344,6 +353,7 @@ class GD_CORE_API ObjectMetadata : public InstructionOrExpressionContainerMetada
|
||||
std::set<gd::String> defaultBehaviorTypes;
|
||||
bool hidden = false;
|
||||
bool isRenderedIn3D = false;
|
||||
gd::String openFullEditorLabel;
|
||||
|
||||
std::shared_ptr<gd::ObjectConfiguration>
|
||||
blueprintObject; ///< The "blueprint" object to be copied when a new
|
||||
|
@@ -808,6 +808,24 @@ gd::String PlatformExtension::GetObjectFullType(const gd::String &extensionName,
|
||||
return extensionName + separator + objectName;
|
||||
}
|
||||
|
||||
gd::String PlatformExtension::GetExtensionFromFullObjectType(const gd::String& type) {
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
if (separatorIndex == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
return type.substr(0, separatorIndex);
|
||||
}
|
||||
|
||||
gd::String PlatformExtension::GetObjectNameFromFullObjectType(const gd::String& type) {
|
||||
const auto separatorIndex =
|
||||
type.find(PlatformExtension::GetNamespaceSeparator());
|
||||
if (separatorIndex == std::string::npos) {
|
||||
return "";
|
||||
}
|
||||
return type.substr(separatorIndex + 2);
|
||||
}
|
||||
|
||||
PlatformExtension::PlatformExtension()
|
||||
: deprecated(false), category(_("General")) {}
|
||||
|
||||
|
@@ -40,8 +40,7 @@ class Object;
|
||||
class ObjectConfiguration;
|
||||
} // namespace gd
|
||||
|
||||
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()>
|
||||
CreateFunPtr;
|
||||
typedef std::function<std::unique_ptr<gd::ObjectConfiguration>()> CreateFunPtr;
|
||||
|
||||
namespace gd {
|
||||
|
||||
@@ -51,25 +50,25 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API CompilationInfo {
|
||||
public:
|
||||
CompilationInfo() : informationCompleted(false){};
|
||||
virtual ~CompilationInfo(){};
|
||||
CompilationInfo() {};
|
||||
virtual ~CompilationInfo() {};
|
||||
|
||||
bool informationCompleted;
|
||||
bool informationCompleted = false;
|
||||
|
||||
bool runtimeOnly; ///< True if the extension was compiled for a runtime use
|
||||
///< only
|
||||
bool runtimeOnly = false; ///< True if the extension was compiled for a
|
||||
///< runtime use only
|
||||
|
||||
#if defined(__GNUC__)
|
||||
int gccMajorVersion;
|
||||
int gccMinorVersion;
|
||||
int gccPatchLevel;
|
||||
int gccMajorVersion = 0;
|
||||
int gccMinorVersion = 0;
|
||||
int gccPatchLevel = 0;
|
||||
#endif
|
||||
|
||||
int sfmlMajorVersion;
|
||||
int sfmlMinorVersion;
|
||||
int sfmlMajorVersion = 0;
|
||||
int sfmlMinorVersion = 0;
|
||||
|
||||
gd::String gdCoreVersion;
|
||||
int sizeOfpInt;
|
||||
int sizeOfpInt = 0;
|
||||
};
|
||||
|
||||
struct GD_CORE_API DuplicatedInstructionOptions {
|
||||
@@ -239,11 +238,12 @@ class GD_CORE_API PlatformExtension {
|
||||
* \param instance The "blueprint" object to be copied when a new object is
|
||||
asked for.
|
||||
*/
|
||||
gd::ObjectMetadata& AddObject(const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_,
|
||||
std::shared_ptr<gd::ObjectConfiguration> instance);
|
||||
gd::ObjectMetadata& AddObject(
|
||||
const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_,
|
||||
std::shared_ptr<gd::ObjectConfiguration> instance);
|
||||
|
||||
/**
|
||||
* \brief Declare a new events based object as being part of the extension.
|
||||
@@ -253,11 +253,10 @@ class GD_CORE_API PlatformExtension {
|
||||
* \param description The user friendly description of the object
|
||||
* \param icon The icon of the object.
|
||||
*/
|
||||
gd::ObjectMetadata& AddEventsBasedObject(
|
||||
const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_);
|
||||
gd::ObjectMetadata& AddEventsBasedObject(const gd::String& name_,
|
||||
const gd::String& fullname_,
|
||||
const gd::String& description_,
|
||||
const gd::String& icon_);
|
||||
|
||||
/**
|
||||
* \brief Declare a new behavior as being part of the extension.
|
||||
@@ -420,8 +419,7 @@ class GD_CORE_API PlatformExtension {
|
||||
PlatformExtension& SetTags(const gd::String& csvTags) {
|
||||
tags.clear();
|
||||
tags = csvTags.Split(',');
|
||||
for (size_t i = 0; i < tags.size(); i++)
|
||||
{
|
||||
for (size_t i = 0; i < tags.size(); i++) {
|
||||
tags[i] = tags[i].Trim().LowerCase();
|
||||
}
|
||||
return *this;
|
||||
@@ -634,26 +632,30 @@ class GD_CORE_API PlatformExtension {
|
||||
*/
|
||||
static gd::String GetNamespaceSeparator() { return "::"; }
|
||||
|
||||
static gd::String GetEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &functionName);
|
||||
static gd::String GetEventsFunctionFullType(const gd::String& extensionName,
|
||||
const gd::String& functionName);
|
||||
|
||||
static gd::String
|
||||
GetBehaviorEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &behaviorName,
|
||||
const gd::String &functionName);
|
||||
static gd::String GetBehaviorEventsFunctionFullType(
|
||||
const gd::String& extensionName,
|
||||
const gd::String& behaviorName,
|
||||
const gd::String& functionName);
|
||||
|
||||
static gd::String GetBehaviorFullType(const gd::String &extensionName,
|
||||
const gd::String &behaviorName);
|
||||
static gd::String GetBehaviorFullType(const gd::String& extensionName,
|
||||
const gd::String& behaviorName);
|
||||
|
||||
static gd::String
|
||||
GetObjectEventsFunctionFullType(const gd::String &extensionName,
|
||||
const gd::String &objectName,
|
||||
const gd::String &functionName);
|
||||
static gd::String GetObjectEventsFunctionFullType(
|
||||
const gd::String& extensionName,
|
||||
const gd::String& objectName,
|
||||
const gd::String& functionName);
|
||||
|
||||
static gd::String GetObjectFullType(const gd::String &extensionName,
|
||||
const gd::String &objectName);
|
||||
static gd::String GetObjectFullType(const gd::String& extensionName,
|
||||
const gd::String& objectName);
|
||||
|
||||
private:
|
||||
static gd::String GetExtensionFromFullObjectType(const gd::String& type);
|
||||
|
||||
static gd::String GetObjectNameFromFullObjectType(const gd::String& type);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Set the namespace (the string all actions/conditions/expressions start
|
||||
* with).
|
||||
@@ -668,10 +670,10 @@ private:
|
||||
gd::String fullname; ///< Name displayed to users in the editor.
|
||||
gd::String informations; ///< Description displayed to users in the editor.
|
||||
gd::String category;
|
||||
gd::String author; ///< Author displayed to users in the editor.
|
||||
gd::String license; ///< License name displayed to users in the editor.
|
||||
bool deprecated; ///< true if the extension is deprecated and shouldn't be
|
||||
///< shown in IDE.
|
||||
gd::String author; ///< Author displayed to users in the editor.
|
||||
gd::String license; ///< License name displayed to users in the editor.
|
||||
bool deprecated; ///< true if the extension is deprecated and shouldn't be
|
||||
///< shown in IDE.
|
||||
gd::String helpPath; ///< The relative path to the help for this extension in
|
||||
///< the documentation.
|
||||
gd::String iconUrl; ///< The URL to the icon to be shown for this extension.
|
||||
|
@@ -5,6 +5,8 @@
|
||||
* project is released under the MIT License.
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
#ifndef GDCORE_PLATFORMEXTENSION_INL
|
||||
#define GDCORE_PLATFORMEXTENSION_INL
|
||||
|
||||
@@ -36,3 +38,5 @@ gd::ObjectMetadata& PlatformExtension::AddObject(const gd::String& name,
|
||||
} // namespace gd
|
||||
|
||||
#endif
|
||||
|
||||
// NOLINTEND
|
@@ -29,9 +29,6 @@ void EventBasedBehaviorBrowser::ExposeEvents(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior, worker);
|
||||
}
|
||||
|
||||
void EventBasedBehaviorBrowser::ExposeObjects(
|
||||
gd::Project &project, gd::ArbitraryObjectsWorker &worker) const {}
|
||||
|
||||
void EventBasedBehaviorBrowser::ExposeFunctions(
|
||||
gd::Project &project, gd::ArbitraryEventsFunctionsWorker &worker) const {
|
||||
worker.Launch(eventsBasedBehavior.GetEventsFunctions());
|
||||
@@ -43,7 +40,4 @@ void EventBasedBehaviorBrowser::ExposeEventBasedBehaviors(
|
||||
worker.Launch(eventsBasedBehavior);
|
||||
}
|
||||
|
||||
void EventBasedBehaviorBrowser::ExposeBehaviorSharedDatas(
|
||||
gd::Project &project, gd::ArbitraryBehaviorSharedDataWorker &worker) const {}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -67,7 +67,7 @@ public:
|
||||
* \brief Do nothing.
|
||||
*/
|
||||
void ExposeObjects(gd::Project &project,
|
||||
gd::ArbitraryObjectsWorker &worker) const override;
|
||||
gd::ArbitraryObjectsWorker &worker) const override {};
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on the event-based behavior.
|
||||
@@ -80,7 +80,7 @@ public:
|
||||
* \brief Do nothing.
|
||||
*/
|
||||
void ExposeBehaviorSharedDatas(gd::Project &project,
|
||||
gd::ArbitraryBehaviorSharedDataWorker &worker) const override;
|
||||
gd::ArbitraryBehaviorSharedDataWorker &worker) const override {};
|
||||
|
||||
private:
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension;
|
||||
|
37
Core/GDCore/IDE/EventBasedObjectBrowser.cpp
Normal file
37
Core/GDCore/IDE/EventBasedObjectBrowser.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "EventBasedObjectBrowser.h"
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
|
||||
#include "GDCore/IDE/ProjectBrowserHelper.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
void EventBasedObjectBrowser::ExposeEvents(
|
||||
gd::Project &project, gd::ArbitraryEventsWorker &worker) const {
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
project, eventsBasedObject, worker);
|
||||
}
|
||||
|
||||
void EventBasedObjectBrowser::ExposeEvents(
|
||||
gd::Project &project, gd::ArbitraryEventsWorkerWithContext &worker) const {
|
||||
gd::ProjectBrowserHelper::ExposeEventsBasedObjectEvents(
|
||||
project, eventsFunctionsExtension, eventsBasedObject, worker);
|
||||
}
|
||||
|
||||
void EventBasedObjectBrowser::ExposeFunctions(
|
||||
gd::Project &project, gd::ArbitraryEventsFunctionsWorker &worker) const {
|
||||
worker.Launch(eventsBasedObject.GetEventsFunctions());
|
||||
}
|
||||
|
||||
} // namespace gd
|
90
Core/GDCore/IDE/EventBasedObjectBrowser.h
Normal file
90
Core/GDCore/IDE/EventBasedObjectBrowser.h
Normal file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* 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 "GDCore/IDE/ProjectBrowser.h"
|
||||
|
||||
namespace gd {
|
||||
class Project;
|
||||
class String;
|
||||
class EventsFunctionsExtension;
|
||||
class EventsFunction;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
class ArbitraryEventsWorker;
|
||||
class ArbitraryEventsWorkerWithContext;
|
||||
class ArbitraryEventsFunctionsWorker;
|
||||
class ArbitraryObjectsWorker;
|
||||
class ArbitraryEventBasedBehaviorsWorker;
|
||||
class ArbitraryBehaviorSharedDataWorker;
|
||||
} // namespace gd
|
||||
|
||||
namespace gd {
|
||||
|
||||
/**
|
||||
* \brief Expose event-based object contents to workers.
|
||||
*/
|
||||
class GD_CORE_API EventBasedObjectBrowser : public ProjectBrowser {
|
||||
public:
|
||||
EventBasedObjectBrowser(
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension_,
|
||||
gd::EventsBasedObject &eventsBasedObject_)
|
||||
: eventsFunctionsExtension(eventsFunctionsExtension_),
|
||||
eventsBasedObject(eventsBasedObject_) {}
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
* object.
|
||||
*
|
||||
* This should be the preferred way to traverse all the events of an event-based object.
|
||||
*/
|
||||
void ExposeEvents(gd::Project &project,
|
||||
gd::ArbitraryEventsWorker &worker) const override;
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all events of the event-based
|
||||
* object.
|
||||
*
|
||||
* This should be the preferred way to traverse all the events of an event-based object.
|
||||
*/
|
||||
void
|
||||
ExposeEvents(gd::Project &project,
|
||||
gd::ArbitraryEventsWorkerWithContext &worker) const override;
|
||||
|
||||
/**
|
||||
* \brief Call the specified worker on all functions of the event-based object
|
||||
*
|
||||
* This should be the preferred way to traverse all the function signatures
|
||||
* of an event-based object.
|
||||
*/
|
||||
void ExposeFunctions(gd::Project &project,
|
||||
gd::ArbitraryEventsFunctionsWorker &worker) const override;
|
||||
|
||||
/**
|
||||
* \brief Do nothing.
|
||||
*/
|
||||
void ExposeObjects(gd::Project &project,
|
||||
gd::ArbitraryObjectsWorker &worker) const override {};
|
||||
|
||||
/**
|
||||
* @brief Do nothing.
|
||||
*/
|
||||
void ExposeEventBasedBehaviors(
|
||||
gd::Project &project,
|
||||
gd::ArbitraryEventBasedBehaviorsWorker &worker) const override {};
|
||||
|
||||
/**
|
||||
* \brief Do nothing.
|
||||
*/
|
||||
void ExposeBehaviorSharedDatas(gd::Project &project,
|
||||
gd::ArbitraryBehaviorSharedDataWorker &worker) const override {};
|
||||
|
||||
private:
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension;
|
||||
gd::EventsBasedObject &eventsBasedObject;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -337,19 +337,19 @@ struct GD_CORE_API ExpressionCompletionDescription {
|
||||
|
||||
private:
|
||||
CompletionKind completionKind;
|
||||
gd::Variable::Type variableType;
|
||||
gd::VariablesContainer::SourceType variableScope;
|
||||
gd::Variable::Type variableType = gd::Variable::Unknown;
|
||||
gd::VariablesContainer::SourceType variableScope = gd::VariablesContainer::Unknown;
|
||||
gd::String type;
|
||||
gd::String prefix;
|
||||
gd::String completion;
|
||||
size_t replacementStartPosition;
|
||||
size_t replacementEndPosition;
|
||||
size_t replacementStartPosition = 0;
|
||||
size_t replacementEndPosition = 0;
|
||||
gd::String objectName;
|
||||
gd::String behaviorName;
|
||||
bool isExact;
|
||||
bool isLastParameter;
|
||||
const gd::ParameterMetadata* parameterMetadata;
|
||||
const gd::ObjectConfiguration* objectConfiguration;
|
||||
bool isExact = false;
|
||||
bool isLastParameter = false;
|
||||
const gd::ParameterMetadata* parameterMetadata = &badParameterMetadata;
|
||||
const gd::ObjectConfiguration* objectConfiguration = &badObjectConfiguration;
|
||||
|
||||
static const gd::ParameterMetadata badParameterMetadata;
|
||||
static const gd::ObjectConfiguration badObjectConfiguration;
|
||||
|
@@ -33,8 +33,10 @@ class GD_CORE_API ExpressionNodeLocationFinder
|
||||
* \brief Initialize the finder to search at the specified position.
|
||||
*/
|
||||
ExpressionNodeLocationFinder(size_t searchedPosition_)
|
||||
: searchedPosition(searchedPosition_), foundNode(nullptr){};
|
||||
virtual ~ExpressionNodeLocationFinder(){};
|
||||
: searchedPosition(searchedPosition_),
|
||||
foundNode(nullptr),
|
||||
parentNode(nullptr) {};
|
||||
virtual ~ExpressionNodeLocationFinder() {};
|
||||
|
||||
/**
|
||||
* \brief Helper function to find the deepest node at the search position, if
|
||||
|
@@ -74,8 +74,8 @@ class GD_CORE_API ExpressionsParameterMover
|
||||
|
||||
const gd::Platform &platform;
|
||||
gd::String functionName;
|
||||
std::size_t oldIndex;
|
||||
std::size_t newIndex;
|
||||
std::size_t oldIndex = 0;
|
||||
std::size_t newIndex = 0;
|
||||
gd::String behaviorType;
|
||||
gd::String objectType;
|
||||
};
|
||||
|
@@ -4,6 +4,7 @@
|
||||
#include "GDCore/Extensions/Metadata/DependencyMetadata.h"
|
||||
#include "GDCore/Extensions/PlatformExtension.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
|
@@ -6,17 +6,9 @@
|
||||
#include "ResourceExposer.h"
|
||||
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/EventsFunctionTools.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryResourceWorker.h"
|
||||
#include "GDCore/IDE/ProjectBrowserHelper.h"
|
||||
#include "GDCore/Project/EventsBasedBehavior.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
#include "GDCore/Project/EventsFunctionsExtension.h"
|
||||
#include "GDCore/Project/ExternalEvents.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/Effect.h"
|
||||
@@ -24,7 +16,6 @@
|
||||
#include "GDCore/Extensions/Platform.h"
|
||||
#include "GDCore/Extensions/Metadata/MetadataProvider.h"
|
||||
#include "GDCore/Extensions/Metadata/EffectMetadata.h"
|
||||
#include "GDCore/IDE/Events/UsedExtensionsFinder.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include "GDCore/IDE/DependenciesAnalyzer.h"
|
||||
#include "GDCore/IDE/GroupVariableHelper.h"
|
||||
#include "GDCore/IDE/EventBasedBehaviorBrowser.h"
|
||||
#include "GDCore/IDE/EventBasedObjectBrowser.h"
|
||||
#include "GDCore/IDE/Events/ArbitraryEventsWorker.h"
|
||||
#include "GDCore/IDE/Events/BehaviorParametersFiller.h"
|
||||
#include "GDCore/IDE/Events/BehaviorTypeRenamer.h"
|
||||
@@ -28,11 +29,6 @@
|
||||
#include "GDCore/IDE/Events/InstructionsTypeRenamer.h"
|
||||
#include "GDCore/IDE/Events/LinkEventTargetRenamer.h"
|
||||
#include "GDCore/IDE/Events/ProjectElementRenamer.h"
|
||||
#include "GDCore/IDE/EventsFunctionTools.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryBehaviorSharedDataWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventBasedBehaviorsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryEventsFunctionsWorker.h"
|
||||
#include "GDCore/IDE/Project/ArbitraryObjectsWorker.h"
|
||||
#include "GDCore/IDE/Project/BehaviorObjectTypeRenamer.h"
|
||||
#include "GDCore/IDE/Project/BehaviorsSharedDataBehaviorTypeRenamer.h"
|
||||
#include "GDCore/IDE/Project/FunctionParameterBehaviorTypeRenamer.h"
|
||||
@@ -415,20 +411,32 @@ void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedBehavior(
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &sourceExtensionName) {
|
||||
const EventBasedBehaviorBrowser eventBasedBehaviorExposer(
|
||||
const EventBasedBehaviorBrowser eventBasedBehaviorBrowser(
|
||||
eventsFunctionsExtension, eventsBasedBehavior);
|
||||
WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
project, eventsFunctionsExtension, sourceExtensionName,
|
||||
eventsFunctionsExtension.GetName(), eventBasedBehaviorExposer);
|
||||
eventsFunctionsExtension.GetName(), eventBasedBehaviorBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::UpdateExtensionNameInEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &sourceExtensionName) {
|
||||
const EventBasedObjectBrowser eventBasedObjectBrowser(
|
||||
eventsFunctionsExtension, eventsBasedObject);
|
||||
WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
project, eventsFunctionsExtension, sourceExtensionName,
|
||||
eventsFunctionsExtension.GetName(), eventBasedObjectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::String &oldName, const gd::String &newName) {
|
||||
const WholeProjectBrowser wholeProjectExposer;
|
||||
const WholeProjectBrowser wholeProjectBrowser;
|
||||
RenameEventsFunctionsExtension(project, eventsFunctionsExtension, oldName,
|
||||
newName, wholeProjectExposer);
|
||||
newName, wholeProjectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsFunctionsExtension(
|
||||
@@ -1312,6 +1320,19 @@ bool WholeProjectRefactorer::FixInvalidRequiredBehaviorProperties(
|
||||
return !invalidRequiredBehaviorProblems.empty();
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::UpdateBehaviorNameInEventsBasedBehavior(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &sourceBehaviorName) {
|
||||
const EventBasedBehaviorBrowser eventBasedBehaviorExposer(
|
||||
eventsFunctionsExtension, eventsBasedBehavior);
|
||||
WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior,
|
||||
sourceBehaviorName, eventsBasedBehavior.GetName(),
|
||||
eventBasedBehaviorExposer);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
@@ -1324,10 +1345,22 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
return;
|
||||
}
|
||||
auto &eventsBasedBehavior = eventsBasedBehaviors.Get(oldBehaviorName);
|
||||
const WholeProjectBrowser projectBrowser;
|
||||
WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
project, eventsFunctionsExtension, eventsBasedBehavior, oldBehaviorName,
|
||||
newBehaviorName, projectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &oldBehaviorName,
|
||||
const gd::String &newBehaviorName,
|
||||
const gd::ProjectBrowser &projectBrowser) {
|
||||
auto renameBehaviorEventsFunction =
|
||||
[&project, &eventsFunctionsExtension, &oldBehaviorName,
|
||||
&newBehaviorName](const gd::EventsFunction &eventsFunction) {
|
||||
&newBehaviorName, &projectBrowser](const gd::EventsFunction &eventsFunction) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
// Nothing to do, expressions are not including the name of the
|
||||
// behavior
|
||||
@@ -1341,12 +1374,12 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName,
|
||||
eventsFunction.GetName()));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer);
|
||||
projectBrowser.ExposeEvents(project, renamer);
|
||||
}
|
||||
};
|
||||
|
||||
auto renameBehaviorProperty = [&project, &eventsFunctionsExtension,
|
||||
&oldBehaviorName, &newBehaviorName](
|
||||
&oldBehaviorName, &newBehaviorName, &projectBrowser](
|
||||
const gd::NamedPropertyDescriptor
|
||||
&property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
@@ -1357,7 +1390,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName,
|
||||
EventsBasedBehavior::GetPropertyActionName(property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer);
|
||||
projectBrowser.ExposeEvents(project, actionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1367,7 +1400,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName,
|
||||
EventsBasedBehavior::GetPropertyConditionName(property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer);
|
||||
projectBrowser.ExposeEvents(project, conditionRenamer);
|
||||
|
||||
// Nothing to do for expression, expressions are not including the name of
|
||||
// the behavior
|
||||
@@ -1375,7 +1408,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
|
||||
auto renameBehaviorSharedProperty =
|
||||
[&project, &eventsFunctionsExtension, &oldBehaviorName,
|
||||
&newBehaviorName](const gd::NamedPropertyDescriptor &property) {
|
||||
&newBehaviorName, &projectBrowser](const gd::NamedPropertyDescriptor &property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
gd::PlatformExtension::GetBehaviorEventsFunctionFullType(
|
||||
@@ -1386,7 +1419,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName,
|
||||
EventsBasedBehavior::GetSharedPropertyActionName(
|
||||
property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer);
|
||||
projectBrowser.ExposeEvents(project, actionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer =
|
||||
gd::InstructionsTypeRenamer(
|
||||
@@ -1399,8 +1432,7 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName,
|
||||
EventsBasedBehavior::GetSharedPropertyConditionName(
|
||||
property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project,
|
||||
conditionRenamer);
|
||||
projectBrowser.ExposeEvents(project, conditionRenamer);
|
||||
|
||||
// Nothing to do for expression, expressions are not including the name
|
||||
// of the behavior
|
||||
@@ -1435,13 +1467,25 @@ void WholeProjectRefactorer::RenameEventsBasedBehavior(
|
||||
renameBehaviorSharedProperty(*property);
|
||||
}
|
||||
|
||||
const WholeProjectBrowser wholeProjectExposer;
|
||||
DoRenameBehavior(project,
|
||||
gd::PlatformExtension::GetBehaviorFullType(
|
||||
eventsFunctionsExtension.GetName(), oldBehaviorName),
|
||||
gd::PlatformExtension::GetBehaviorFullType(
|
||||
eventsFunctionsExtension.GetName(), newBehaviorName),
|
||||
wholeProjectExposer);
|
||||
projectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::UpdateObjectNameInEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &sourceObjectName) {
|
||||
const EventBasedObjectBrowser eventBasedObjectBrowser(
|
||||
eventsFunctionsExtension, eventsBasedObject);
|
||||
WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
project, eventsFunctionsExtension, eventsBasedObject,
|
||||
sourceObjectName, eventsBasedObject.GetName(),
|
||||
eventBasedObjectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
@@ -1455,10 +1499,21 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
return;
|
||||
}
|
||||
auto &eventsBasedObject = eventsBasedObjects.Get(oldObjectName);
|
||||
const WholeProjectBrowser projectBrowser;
|
||||
WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
project, eventsFunctionsExtension, eventsBasedObject, oldObjectName,
|
||||
newObjectName, projectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &oldObjectName, const gd::String &newObjectName,
|
||||
const gd::ProjectBrowser &projectBrowser) {
|
||||
auto renameObjectEventsFunction =
|
||||
[&project, &eventsFunctionsExtension, &oldObjectName,
|
||||
&newObjectName](const gd::EventsFunction &eventsFunction) {
|
||||
[&project, &eventsFunctionsExtension, &oldObjectName, &newObjectName,
|
||||
&projectBrowser](const gd::EventsFunction &eventsFunction) {
|
||||
if (eventsFunction.IsExpression()) {
|
||||
// Nothing to do, expressions are not including the name of the
|
||||
// object
|
||||
@@ -1472,12 +1527,12 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newObjectName,
|
||||
eventsFunction.GetName()));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, renamer);
|
||||
projectBrowser.ExposeEvents(project, renamer);
|
||||
}
|
||||
};
|
||||
|
||||
auto renameObjectProperty = [&project, &eventsFunctionsExtension,
|
||||
&oldObjectName, &newObjectName](
|
||||
&oldObjectName, &newObjectName, &projectBrowser](
|
||||
const gd::NamedPropertyDescriptor &property) {
|
||||
gd::InstructionsTypeRenamer actionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1487,7 +1542,7 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newObjectName,
|
||||
EventsBasedObject::GetPropertyActionName(property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, actionRenamer);
|
||||
projectBrowser.ExposeEvents(project, actionRenamer);
|
||||
|
||||
gd::InstructionsTypeRenamer conditionRenamer = gd::InstructionsTypeRenamer(
|
||||
project,
|
||||
@@ -1497,7 +1552,7 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
gd::PlatformExtension::GetObjectEventsFunctionFullType(
|
||||
eventsFunctionsExtension.GetName(), newObjectName,
|
||||
EventsBasedObject::GetPropertyConditionName(property.GetName())));
|
||||
gd::ProjectBrowserHelper::ExposeProjectEvents(project, conditionRenamer);
|
||||
projectBrowser.ExposeEvents(project, conditionRenamer);
|
||||
|
||||
// Nothing to do for expression, expressions are not including the name of
|
||||
// the object
|
||||
@@ -1528,13 +1583,12 @@ void WholeProjectRefactorer::RenameEventsBasedObject(
|
||||
renameObjectProperty(*property);
|
||||
}
|
||||
|
||||
const WholeProjectBrowser wholeProjectExposer;
|
||||
DoRenameObject(project,
|
||||
gd::PlatformExtension::GetObjectFullType(
|
||||
eventsFunctionsExtension.GetName(), oldObjectName),
|
||||
gd::PlatformExtension::GetObjectFullType(
|
||||
eventsFunctionsExtension.GetName(), newObjectName),
|
||||
wholeProjectExposer);
|
||||
projectBrowser);
|
||||
}
|
||||
|
||||
void WholeProjectRefactorer::DoRenameEventsFunction(
|
||||
|
@@ -27,14 +27,7 @@ class ObjectsContainer;
|
||||
class VariablesContainer;
|
||||
class EventsBasedBehavior;
|
||||
class EventsBasedObject;
|
||||
class ArbitraryEventsWorker;
|
||||
class ArbitraryObjectsWorker;
|
||||
class ArbitraryEventsFunctionsWorker;
|
||||
class ArbitraryEventsWorkerWithContext;
|
||||
class ArbitraryEventBasedBehaviorsWorker;
|
||||
class ArbitraryBehaviorSharedDataWorker;
|
||||
class Behavior;
|
||||
class BehaviorMetadata;
|
||||
class UnfilledRequiredBehaviorPropertyProblem;
|
||||
class ProjectBrowser;
|
||||
class SerializerElement;
|
||||
@@ -121,14 +114,24 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& newName);
|
||||
|
||||
/**
|
||||
* \brief Refactor behavior events after the extension was placed in a new
|
||||
* \brief Refactor behavior events after the behavior has been placed in a new
|
||||
* extension.
|
||||
*/
|
||||
static void UpdateExtensionNameInEventsBasedBehavior(
|
||||
gd::Project& project,
|
||||
const gd::EventsFunctionsExtension& eventsFunctionsExtension,
|
||||
gd::EventsBasedBehavior& eventsBasedBehavior,
|
||||
const gd::String& sourceExtensionName);
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &sourceExtensionName);
|
||||
|
||||
/**
|
||||
* \brief Refactor object events after the object has been placed in a new
|
||||
* extension.
|
||||
*/
|
||||
static void UpdateExtensionNameInEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &sourceExtensionName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** an events function is renamed.
|
||||
@@ -324,6 +327,16 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& oldBehaviorName,
|
||||
const gd::String& newBehaviorName);
|
||||
|
||||
/**
|
||||
* \brief Refactor events-based behavior events after the events-based
|
||||
* behavior has been duplicated.
|
||||
*/
|
||||
static void UpdateBehaviorNameInEventsBasedBehavior(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &sourceBehaviorName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** an object is renamed.
|
||||
*
|
||||
@@ -337,6 +350,16 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& oldObjectName,
|
||||
const gd::String& newObjectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor events-based object events after the events-based object
|
||||
* has been duplicated.
|
||||
*/
|
||||
static void UpdateObjectNameInEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &sourceObjectName);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project after a layout is renamed.
|
||||
*/
|
||||
@@ -654,6 +677,35 @@ class GD_CORE_API WholeProjectRefactorer {
|
||||
const gd::String& newName,
|
||||
const gd::ProjectBrowser& projectBrowser);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** a behavior is renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified behavior after calling this.
|
||||
* This is because the behavior is expected to have its old name for the
|
||||
* refactoring.
|
||||
*/
|
||||
static void RenameEventsBasedBehavior(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedBehavior &eventsBasedBehavior,
|
||||
const gd::String &oldBehaviorName,
|
||||
const gd::String &newBehaviorName,
|
||||
const gd::ProjectBrowser &projectBrowser);
|
||||
|
||||
/**
|
||||
* \brief Refactor the project **before** an object is renamed.
|
||||
*
|
||||
* \warning Do the renaming of the specified object after calling this.
|
||||
* This is because the object is expected to have its old name for the
|
||||
* refactoring.
|
||||
*/
|
||||
static void RenameEventsBasedObject(
|
||||
gd::Project &project,
|
||||
const gd::EventsFunctionsExtension &eventsFunctionsExtension,
|
||||
const gd::EventsBasedObject &eventsBasedObject,
|
||||
const gd::String &oldObjectName, const gd::String &newObjectName,
|
||||
const gd::ProjectBrowser &projectBrowser);
|
||||
|
||||
static void FindDependentBehaviorNames(
|
||||
const gd::Project& project,
|
||||
const gd::Object& object,
|
||||
|
@@ -8,8 +8,10 @@
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
|
||||
#include "GDCore/Project/QuickCustomization.h"
|
||||
#include "GDCore/Project/QuickCustomizationVisibilitiesContainer.h"
|
||||
#include "GDCore/Serialization/Serializer.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
@@ -32,12 +34,21 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API BehaviorConfigurationContainer {
|
||||
public:
|
||||
BehaviorConfigurationContainer() : folded(false), quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
|
||||
BehaviorConfigurationContainer()
|
||||
: folded(false),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default),
|
||||
propertiesQuickCustomizationVisibilities() {};
|
||||
BehaviorConfigurationContainer(const gd::String& name_,
|
||||
const gd::String& type_)
|
||||
: name(name_), type(type_), folded(false), quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
|
||||
: name(name_),
|
||||
type(type_),
|
||||
folded(false),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default),
|
||||
propertiesQuickCustomizationVisibilities() {};
|
||||
virtual ~BehaviorConfigurationContainer();
|
||||
virtual BehaviorConfigurationContainer* Clone() const { return new BehaviorConfigurationContainer(*this); }
|
||||
virtual BehaviorConfigurationContainer* Clone() const {
|
||||
return new BehaviorConfigurationContainer(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return the name identifying the behavior
|
||||
@@ -68,7 +79,6 @@ class GD_CORE_API BehaviorConfigurationContainer {
|
||||
*/
|
||||
std::map<gd::String, gd::PropertyDescriptor> GetProperties() const;
|
||||
|
||||
|
||||
/**
|
||||
* \brief Called when the IDE wants to update a custom property of the
|
||||
* behavior
|
||||
@@ -84,9 +94,7 @@ class GD_CORE_API BehaviorConfigurationContainer {
|
||||
* \brief Called to initialize the content with the default properties
|
||||
* for the behavior.
|
||||
*/
|
||||
virtual void InitializeContent() {
|
||||
InitializeContent(content);
|
||||
};
|
||||
virtual void InitializeContent() { InitializeContent(content); };
|
||||
|
||||
/**
|
||||
* \brief Serialize the behavior content.
|
||||
@@ -115,15 +123,42 @@ class GD_CORE_API BehaviorConfigurationContainer {
|
||||
*/
|
||||
bool IsFolded() const { return folded; }
|
||||
|
||||
void SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
|
||||
/**
|
||||
* @brief Set if the whole behavior should be visible or not in the Quick
|
||||
* Customization.
|
||||
*/
|
||||
void SetQuickCustomizationVisibility(
|
||||
QuickCustomization::Visibility visibility) {
|
||||
quickCustomizationVisibility = visibility;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get if the whole behavior should be visible or not in the Quick
|
||||
* Customization.
|
||||
*/
|
||||
QuickCustomization::Visibility GetQuickCustomizationVisibility() const {
|
||||
return quickCustomizationVisibility;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Get the map of properties and their visibility in the Quick
|
||||
* Customization.
|
||||
*/
|
||||
QuickCustomizationVisibilitiesContainer&
|
||||
GetPropertiesQuickCustomizationVisibilities() {
|
||||
return propertiesQuickCustomizationVisibilities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the map of properties and their visibility in the Quick
|
||||
* Customization.
|
||||
*/
|
||||
const QuickCustomizationVisibilitiesContainer&
|
||||
GetPropertiesQuickCustomizationVisibilities() const {
|
||||
return propertiesQuickCustomizationVisibilities;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* \brief Called when the IDE wants to know about the custom properties of the
|
||||
* behavior.
|
||||
@@ -159,7 +194,7 @@ protected:
|
||||
* \brief Called to initialize the content with the default properties
|
||||
* for the behavior.
|
||||
*/
|
||||
virtual void InitializeContent(gd::SerializerElement& behaviorContent){};
|
||||
virtual void InitializeContent(gd::SerializerElement& behaviorContent) {};
|
||||
|
||||
private:
|
||||
gd::String name; ///< Name of the behavior
|
||||
@@ -169,6 +204,8 @@ protected:
|
||||
gd::SerializerElement content; // Storage for the behavior properties
|
||||
bool folded;
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
QuickCustomizationVisibilitiesContainer
|
||||
propertiesQuickCustomizationVisibilities;
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -272,3 +272,16 @@ const SpriteAnimationList& CustomObjectConfiguration::GetAnimations() const {
|
||||
SpriteAnimationList& CustomObjectConfiguration::GetAnimations() {
|
||||
return animations;
|
||||
}
|
||||
|
||||
const gd::CustomObjectConfiguration::EdgeAnchor
|
||||
CustomObjectConfiguration::GetEdgeAnchorFromString(const gd::String &value) {
|
||||
return (value == _("Window left") || value == _("Window top"))
|
||||
? gd::CustomObjectConfiguration::EdgeAnchor::MinEdge
|
||||
: (value == _("Window right") || value == _("Window bottom"))
|
||||
? gd::CustomObjectConfiguration::EdgeAnchor::MaxEdge
|
||||
: value == _("Proportional")
|
||||
? gd::CustomObjectConfiguration::EdgeAnchor::Proportional
|
||||
: value == _("Window center")
|
||||
? gd::CustomObjectConfiguration::EdgeAnchor::Center
|
||||
: gd::CustomObjectConfiguration::EdgeAnchor::NoAnchor;
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_set>
|
||||
#include "GDCore/Project/Object.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/EventsBasedObject.h"
|
||||
@@ -98,6 +99,38 @@ class CustomObjectConfiguration : public gd::ObjectConfiguration {
|
||||
*/
|
||||
SpriteAnimationList& GetAnimations();
|
||||
|
||||
enum EdgeAnchor {
|
||||
NoAnchor = 0,
|
||||
MinEdge = 1,
|
||||
MaxEdge = 2,
|
||||
Proportional = 3,
|
||||
Center = 4,
|
||||
};
|
||||
|
||||
static const gd::CustomObjectConfiguration::EdgeAnchor
|
||||
GetEdgeAnchorFromString(const gd::String &value);
|
||||
|
||||
/**
|
||||
* Check if a child object properties must be displayed as folded in the editor.
|
||||
* This is only useful when the object can override its children configuration (which
|
||||
* is something being deprecated).
|
||||
*/
|
||||
bool IsChildObjectFolded(const gd::String& childName) const {
|
||||
return unfoldedChildren.find(childName) == unfoldedChildren.end();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set if a child object properties must be displayed as folded in the editor.
|
||||
* This is only useful when the object can override its children configuration (which
|
||||
* is something being deprecated).
|
||||
*/
|
||||
void SetChildObjectFolded(const gd::String& childName, bool folded) {
|
||||
if (!folded)
|
||||
unfoldedChildren.insert(childName);
|
||||
else
|
||||
unfoldedChildren.erase(childName);
|
||||
}
|
||||
|
||||
protected:
|
||||
void DoSerializeTo(SerializerElement& element) const override;
|
||||
void DoUnserializeFrom(Project& project, const SerializerElement& element) override;
|
||||
@@ -107,11 +140,12 @@ protected:
|
||||
|
||||
bool IsOverridingEventsBasedObjectChildrenConfiguration() const;
|
||||
|
||||
const Project* project; ///< The project is used to get the
|
||||
///< EventBasedObject from the fullType.
|
||||
const Project* project = nullptr; ///< The project is used to get the
|
||||
///< EventBasedObject from the fullType.
|
||||
gd::SerializerElement objectContent;
|
||||
|
||||
bool isMarkedAsOverridingEventsBasedObjectChildrenConfiguration;
|
||||
std::unordered_set<gd::String> unfoldedChildren;
|
||||
|
||||
bool isMarkedAsOverridingEventsBasedObjectChildrenConfiguration = false;
|
||||
mutable std::map<gd::String, std::unique_ptr<gd::ObjectConfiguration>> childObjectConfigurations;
|
||||
|
||||
static gd::ObjectConfiguration badObjectConfiguration;
|
||||
|
@@ -12,6 +12,7 @@ namespace gd {
|
||||
void Effect::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", GetName());
|
||||
element.SetAttribute("effectType", GetEffectType());
|
||||
if (IsFolded()) element.SetBoolAttribute("folded", true);
|
||||
|
||||
SerializerElement& doubleParametersElement =
|
||||
element.AddChild("doubleParameters");
|
||||
@@ -41,6 +42,7 @@ void Effect::UnserializeFrom(const SerializerElement& element) {
|
||||
"effectName"
|
||||
// end of compatibility code
|
||||
));
|
||||
SetFolded(element.GetBoolAttribute("folded", false));
|
||||
|
||||
doubleParameters.clear();
|
||||
const SerializerElement& doubleParametersElement =
|
||||
|
@@ -21,8 +21,8 @@ namespace gd {
|
||||
*/
|
||||
class GD_CORE_API Effect {
|
||||
public:
|
||||
Effect(){};
|
||||
virtual ~Effect(){};
|
||||
Effect() : folded(false) {};
|
||||
virtual ~Effect() {};
|
||||
|
||||
void SetName(const gd::String& name_) { name = name_; }
|
||||
const gd::String& GetName() const { return name; }
|
||||
@@ -32,6 +32,9 @@ class GD_CORE_API Effect {
|
||||
}
|
||||
const gd::String& GetEffectType() const { return effectType; }
|
||||
|
||||
void SetFolded(bool fold = true) { folded = fold; }
|
||||
bool IsFolded() const { return folded; }
|
||||
|
||||
void SetDoubleParameter(const gd::String& name, double value) {
|
||||
doubleParameters[name] = value;
|
||||
}
|
||||
@@ -85,6 +88,7 @@ class GD_CORE_API Effect {
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
private:
|
||||
bool folded;
|
||||
gd::String name; ///< The name of the layer.
|
||||
gd::String effectType; ///< The name of the effect to apply.
|
||||
std::map<gd::String, double> doubleParameters; ///< Values of parameters being doubles, keyed by names.
|
||||
|
@@ -17,6 +17,7 @@ EventsBasedObject::EventsBasedObject()
|
||||
isAnimatable(false),
|
||||
isTextContainer(false),
|
||||
isInnerAreaFollowingParentSize(false),
|
||||
isUsingLegacyInstancesRenderer(false),
|
||||
areaMinX(0),
|
||||
areaMinY(0),
|
||||
areaMinZ(0),
|
||||
@@ -41,6 +42,7 @@ void EventsBasedObject::SerializeTo(SerializerElement& element) const {
|
||||
if (isInnerAreaFollowingParentSize) {
|
||||
element.SetBoolAttribute("isInnerAreaFollowingParentSize", true);
|
||||
}
|
||||
element.SetBoolAttribute("isUsingLegacyInstancesRenderer", isUsingLegacyInstancesRenderer);
|
||||
element.SetIntAttribute("areaMinX", areaMinX);
|
||||
element.SetIntAttribute("areaMinY", areaMinY);
|
||||
element.SetIntAttribute("areaMinZ", areaMinZ);
|
||||
@@ -88,6 +90,15 @@ void EventsBasedObject::UnserializeFrom(gd::Project& project,
|
||||
}
|
||||
|
||||
initialInstances.UnserializeFrom(element.GetChild("instances"));
|
||||
if (element.HasAttribute("isUsingLegacyInstancesRenderer")) {
|
||||
isUsingLegacyInstancesRenderer =
|
||||
element.GetBoolAttribute("isUsingLegacyInstancesRenderer", false);
|
||||
}
|
||||
else {
|
||||
// Compatibility with GD <= 5.4.212
|
||||
isUsingLegacyInstancesRenderer = initialInstances.GetInstancesCount() == 0;
|
||||
// end of compatibility code
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -111,7 +111,7 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
|
||||
* adapt there size. This is removing the ScalableCapability.
|
||||
*/
|
||||
EventsBasedObject &
|
||||
MarkAsInnerAreaExpandingWithParent(bool isInnerAreaExpandingWithParent_) {
|
||||
MarkAsInnerAreaFollowingParentSize(bool isInnerAreaExpandingWithParent_) {
|
||||
isInnerAreaFollowingParentSize = isInnerAreaExpandingWithParent_;
|
||||
return *this;
|
||||
}
|
||||
@@ -130,6 +130,24 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
|
||||
return isInnerAreaFollowingParentSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Declare that custom object are rendered using their child-objects
|
||||
* instead of their child-instances.
|
||||
*/
|
||||
EventsBasedObject &
|
||||
MakAsUsingLegacyInstancesRenderer(bool isUsingLegacyInstancesRenderer_) {
|
||||
isUsingLegacyInstancesRenderer = isUsingLegacyInstancesRenderer_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if custom object are rendered using their child-objects
|
||||
* instead of their child-instances.
|
||||
*/
|
||||
bool IsUsingLegacyInstancesRenderer() const {
|
||||
return isUsingLegacyInstancesRenderer;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Return true if the object needs a TextContainer capability.
|
||||
*/
|
||||
@@ -304,6 +322,7 @@ class GD_CORE_API EventsBasedObject: public AbstractEventsBasedEntity {
|
||||
bool isAnimatable;
|
||||
bool isTextContainer;
|
||||
bool isInnerAreaFollowingParentSize;
|
||||
bool isUsingLegacyInstancesRenderer;
|
||||
gd::InitialInstancesContainer initialInstances;
|
||||
gd::LayersContainer layers;
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
|
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace gd {
|
||||
|
||||
ExternalEvents::ExternalEvents() : lastChangeTimeStamp(0) {
|
||||
ExternalEvents::ExternalEvents() {
|
||||
// ctor
|
||||
}
|
||||
|
||||
@@ -24,14 +24,12 @@ ExternalEvents& ExternalEvents::operator=(const ExternalEvents& rhs) {
|
||||
void ExternalEvents::Init(const ExternalEvents& externalEvents) {
|
||||
name = externalEvents.GetName();
|
||||
associatedScene = externalEvents.GetAssociatedLayout();
|
||||
lastChangeTimeStamp = externalEvents.GetLastChangeTimeStamp();
|
||||
events = externalEvents.events;
|
||||
}
|
||||
|
||||
void ExternalEvents::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("name", name);
|
||||
element.SetAttribute("associatedLayout", associatedScene);
|
||||
element.SetAttribute("lastChangeTimeStamp", (int)lastChangeTimeStamp);
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
}
|
||||
@@ -41,8 +39,6 @@ void ExternalEvents::UnserializeFrom(gd::Project& project,
|
||||
name = element.GetStringAttribute("name", "", "Name");
|
||||
associatedScene =
|
||||
element.GetStringAttribute("associatedLayout", "", "AssociatedScene");
|
||||
lastChangeTimeStamp =
|
||||
element.GetIntAttribute("lastChangeTimeStamp", 0, "LastChangeTimeStamp");
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, events, element.GetChild("events", 0, "Events"));
|
||||
}
|
||||
|
@@ -67,24 +67,6 @@ class GD_CORE_API ExternalEvents {
|
||||
associatedScene = name_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the latest time of the build.
|
||||
* Used when the IDE found that the external events can be compiled separately
|
||||
* from scene's events.
|
||||
*
|
||||
* \todo This is specific to GD C++ Platform
|
||||
*/
|
||||
time_t GetLastChangeTimeStamp() const { return lastChangeTimeStamp; };
|
||||
|
||||
/**
|
||||
* Change the latest time of the build of the external events.
|
||||
*
|
||||
* \todo This is specific to GD C++ Platform
|
||||
*/
|
||||
void SetLastChangeTimeStamp(time_t newTimeStamp) {
|
||||
lastChangeTimeStamp = newTimeStamp;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the events.
|
||||
*/
|
||||
@@ -109,7 +91,6 @@ class GD_CORE_API ExternalEvents {
|
||||
private:
|
||||
gd::String name;
|
||||
gd::String associatedScene;
|
||||
time_t lastChangeTimeStamp; ///< Time of the last build
|
||||
gd::EventsList events; ///< List of events
|
||||
|
||||
/**
|
||||
@@ -119,19 +100,6 @@ class GD_CORE_API ExternalEvents {
|
||||
void Init(const ExternalEvents& externalEvents);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Functor testing ExternalEvents' name
|
||||
*/
|
||||
struct ExternalEventsHasName
|
||||
: public std::binary_function<std::unique_ptr<gd::ExternalEvents>,
|
||||
gd::String,
|
||||
bool> {
|
||||
bool operator()(const std::unique_ptr<gd::ExternalEvents>& externalEvents,
|
||||
gd::String name) const {
|
||||
return externalEvents->GetName() == name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXTERNALEVENTS_H
|
||||
|
@@ -96,19 +96,6 @@ class GD_CORE_API ExternalLayout {
|
||||
gd::String associatedLayout;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Functor testing ExternalLayout' name
|
||||
*/
|
||||
struct ExternalLayoutHasName
|
||||
: public std::binary_function<std::unique_ptr<gd::ExternalLayout>,
|
||||
gd::String,
|
||||
bool> {
|
||||
bool operator()(const std::unique_ptr<gd::ExternalLayout>& externalLayout,
|
||||
gd::String name) const {
|
||||
return externalLayout->GetName() == name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // GDCORE_EXTERNALLAYOUT_H
|
||||
|
@@ -27,7 +27,11 @@ InitialInstance::InitialInstance()
|
||||
rotationX(0),
|
||||
rotationY(0),
|
||||
zOrder(0),
|
||||
opacity(255),
|
||||
layer(""),
|
||||
flippedX(false),
|
||||
flippedY(false),
|
||||
flippedZ(false),
|
||||
customSize(false),
|
||||
customDepth(false),
|
||||
width(0),
|
||||
@@ -57,7 +61,11 @@ void InitialInstance::UnserializeFrom(const SerializerElement& element) {
|
||||
SetHasCustomDepth(false);
|
||||
}
|
||||
SetZOrder(element.GetIntAttribute("zOrder", 0, "plan"));
|
||||
SetOpacity(element.GetIntAttribute("opacity", 255));
|
||||
SetLayer(element.GetStringAttribute("layer"));
|
||||
SetFlippedX(element.GetBoolAttribute("flippedX", false));
|
||||
SetFlippedY(element.GetBoolAttribute("flippedY", false));
|
||||
SetFlippedZ(element.GetBoolAttribute("flippedZ", false));
|
||||
SetLocked(element.GetBoolAttribute("locked", false));
|
||||
SetSealed(element.GetBoolAttribute("sealed", false));
|
||||
SetShouldKeepRatio(element.GetBoolAttribute("keepRatio", false));
|
||||
@@ -113,6 +121,10 @@ void InitialInstance::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("y", GetY());
|
||||
if (GetZ() != 0) element.SetAttribute("z", GetZ());
|
||||
element.SetAttribute("zOrder", GetZOrder());
|
||||
if (GetOpacity() != 255) element.SetAttribute("opacity", GetOpacity());
|
||||
if (IsFlippedX()) element.SetAttribute("flippedX", IsFlippedX());
|
||||
if (IsFlippedY()) element.SetAttribute("flippedY", IsFlippedY());
|
||||
if (IsFlippedZ()) element.SetAttribute("flippedZ", IsFlippedZ());
|
||||
element.SetAttribute("layer", GetLayer());
|
||||
element.SetAttribute("angle", GetAngle());
|
||||
if (GetRotationX() != 0) element.SetAttribute("rotationX", GetRotationX());
|
||||
@@ -155,8 +167,8 @@ InitialInstance& InitialInstance::ResetPersistentUuid() {
|
||||
|
||||
std::map<gd::String, gd::PropertyDescriptor>
|
||||
InitialInstance::GetCustomProperties(
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer) {
|
||||
gd::ObjectsContainer& globalObjectsContainer,
|
||||
gd::ObjectsContainer& objectsContainer) {
|
||||
// Find an object
|
||||
if (objectsContainer.HasObjectNamed(GetObjectName()))
|
||||
return objectsContainer.GetObject(GetObjectName())
|
||||
@@ -172,9 +184,10 @@ InitialInstance::GetCustomProperties(
|
||||
}
|
||||
|
||||
bool InitialInstance::UpdateCustomProperty(
|
||||
const gd::String &name, const gd::String &value,
|
||||
gd::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer) {
|
||||
const gd::String& name,
|
||||
const gd::String& value,
|
||||
gd::ObjectsContainer& globalObjectsContainer,
|
||||
gd::ObjectsContainer& objectsContainer) {
|
||||
if (objectsContainer.HasObjectNamed(GetObjectName()))
|
||||
return objectsContainer.GetObject(GetObjectName())
|
||||
.GetConfiguration()
|
||||
|
@@ -29,7 +29,7 @@ class GD_CORE_API InitialInstance {
|
||||
* \brief Create an initial instance pointing to no object, at position (0,0).
|
||||
*/
|
||||
InitialInstance();
|
||||
virtual ~InitialInstance(){};
|
||||
virtual ~InitialInstance() {};
|
||||
|
||||
/**
|
||||
* Must return a pointer to a copy of the object. A such method is needed to
|
||||
@@ -123,6 +123,46 @@ class GD_CORE_API InitialInstance {
|
||||
*/
|
||||
void SetZOrder(int zOrder_) { zOrder = zOrder_; }
|
||||
|
||||
/**
|
||||
* \brief Get Opacity.
|
||||
*/
|
||||
int GetOpacity() const { return opacity; }
|
||||
|
||||
/**
|
||||
* \brief Set the opacity of the instance.
|
||||
*/
|
||||
void SetOpacity(int opacity_) { opacity = opacity_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the instance is flipped on X axis.
|
||||
*/
|
||||
bool IsFlippedX() const { return flippedX; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance is flipped on X axis.
|
||||
*/
|
||||
void SetFlippedX(bool flippedX_) { flippedX = flippedX_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the instance is flipped on Y axis.
|
||||
*/
|
||||
bool IsFlippedY() const { return flippedY; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance is flipped on Y axis.
|
||||
*/
|
||||
void SetFlippedY(bool flippedY_) { flippedY = flippedY_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the instance is flipped on Z axis.
|
||||
*/
|
||||
bool IsFlippedZ() const { return flippedZ; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance is flipped on Z axis.
|
||||
*/
|
||||
void SetFlippedZ(bool flippedZ_) { flippedZ = flippedZ_; }
|
||||
|
||||
/**
|
||||
* \brief Get the layer the instance belongs to.
|
||||
*/
|
||||
@@ -134,8 +174,9 @@ class GD_CORE_API InitialInstance {
|
||||
void SetLayer(const gd::String& layer_) { layer = layer_; }
|
||||
|
||||
/**
|
||||
* \brief Return true if the instance has a width/height which is different from its
|
||||
* object default width/height. This is independent from `HasCustomDepth`.
|
||||
* \brief Return true if the instance has a width/height which is different
|
||||
* from its object default width/height. This is independent from
|
||||
* `HasCustomDepth`.
|
||||
*
|
||||
* \see gd::Object
|
||||
*/
|
||||
@@ -150,15 +191,13 @@ class GD_CORE_API InitialInstance {
|
||||
bool HasCustomDepth() const { return customDepth; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance has a width/height which is different from its
|
||||
* object default width/height or not.
|
||||
* This is independent from `SetHasCustomDepth`.
|
||||
* \brief Set whether the instance has a width/height which is different from
|
||||
* its object default width/height or not. This is independent from
|
||||
* `SetHasCustomDepth`.
|
||||
*
|
||||
* \see gd::Object
|
||||
*/
|
||||
void SetHasCustomSize(bool hasCustomSize_) {
|
||||
customSize = hasCustomSize_;
|
||||
}
|
||||
void SetHasCustomSize(bool hasCustomSize_) { customSize = hasCustomSize_; }
|
||||
|
||||
/**
|
||||
* \brief Set whether the instance has a depth which is different from its
|
||||
@@ -264,18 +303,19 @@ 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::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer);
|
||||
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::ObjectsContainer &globalObjectsContainer,
|
||||
gd::ObjectsContainer &objectsContainer);
|
||||
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.
|
||||
@@ -343,6 +383,10 @@ class GD_CORE_API InitialInstance {
|
||||
double rotationX; ///< Instance angle on X axis (for a 3D object)
|
||||
double rotationY; ///< Instance angle on Y axis (for a 3D object)
|
||||
int zOrder; ///< Instance Z order (for a 2D object)
|
||||
int opacity; ///< Instance opacity
|
||||
bool flippedX; ///< True if the instance is flipped on X axis
|
||||
bool flippedY; ///< True if the instance is flipped on Y axis
|
||||
bool flippedZ; ///< True if the instance is flipped on Z axis
|
||||
gd::String layer; ///< Instance layer
|
||||
bool customSize; ///< True if object has a custom width and height
|
||||
bool customDepth; ///< True if object has a custom depth
|
||||
@@ -352,13 +396,13 @@ class GD_CORE_API InitialInstance {
|
||||
gd::VariablesContainer initialVariables; ///< Instance specific variables
|
||||
bool locked; ///< True if the instance is locked
|
||||
bool sealed; ///< True if the instance is sealed
|
||||
bool keepRatio; ///< True if the instance's dimensions
|
||||
/// should keep the same ratio.
|
||||
bool keepRatio; ///< True if the instance's dimensions
|
||||
/// should keep the same ratio.
|
||||
mutable gd::String persistentUuid; ///< A persistent random version 4 UUID,
|
||||
/// useful for hot reloading.
|
||||
|
||||
static gd::String*
|
||||
badStringPropertyValue; ///< Empty string returned by GetRawStringProperty
|
||||
static gd::String* badStringPropertyValue; ///< Empty string returned by
|
||||
///< GetRawStringProperty
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -163,6 +163,20 @@ bool InitialInstancesContainer::HasInstancesOfObject(
|
||||
});
|
||||
}
|
||||
|
||||
bool InitialInstancesContainer::IsInstancesCountOfObjectGreaterThan(
|
||||
const gd::String &objectName, const std::size_t minInstanceCount) const {
|
||||
std::size_t count = 0;
|
||||
for (const gd::InitialInstance &instance : initialInstances) {
|
||||
if (instance.GetObjectName() == objectName) {
|
||||
count++;
|
||||
if (count > minInstanceCount) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void InitialInstancesContainer::Create(
|
||||
const InitialInstancesContainer& source) {
|
||||
try {
|
||||
|
@@ -153,6 +153,13 @@ class GD_CORE_API InitialInstancesContainer {
|
||||
*/
|
||||
bool HasInstancesOfObject(const gd::String &objectName) const;
|
||||
|
||||
/**
|
||||
* \brief Return true if there is at least N instances of the given object.
|
||||
*/
|
||||
bool
|
||||
IsInstancesCountOfObjectGreaterThan(const gd::String &objectName,
|
||||
const std::size_t minInstanceCount) const;
|
||||
|
||||
/**
|
||||
* \brief Remove all instances
|
||||
*/
|
||||
|
@@ -24,10 +24,11 @@
|
||||
#include "GDCore/Project/ObjectGroup.h"
|
||||
#include "GDCore/Project/ObjectGroupsContainer.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Project/QuickCustomization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/PolymorphicClone.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
#include "GDCore/Tools/PolymorphicClone.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -43,7 +44,7 @@ Layout& Layout::operator=(const Layout& other) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
Layout::~Layout(){};
|
||||
Layout::~Layout() {};
|
||||
|
||||
Layout::Layout()
|
||||
: backgroundColorR(209),
|
||||
@@ -52,9 +53,7 @@ Layout::Layout()
|
||||
stopSoundsOnStartup(true),
|
||||
standardSortMethod(true),
|
||||
disableInputWhenNotFocused(true),
|
||||
variables(gd::VariablesContainer::SourceType::Scene)
|
||||
{
|
||||
}
|
||||
variables(gd::VariablesContainer::SourceType::Scene) {}
|
||||
|
||||
void Layout::SetName(const gd::String& name_) {
|
||||
name = name_;
|
||||
@@ -102,7 +101,9 @@ const gd::Layer& Layout::GetLayer(const gd::String& name) const {
|
||||
return layers.GetLayer(name);
|
||||
}
|
||||
|
||||
gd::Layer& Layout::GetLayer(std::size_t index) { return layers.GetLayer(index); }
|
||||
gd::Layer& Layout::GetLayer(std::size_t index) {
|
||||
return layers.GetLayer(index);
|
||||
}
|
||||
|
||||
const gd::Layer& Layout::GetLayer(std::size_t index) const {
|
||||
return layers.GetLayer(index);
|
||||
@@ -125,9 +126,7 @@ void Layout::InsertLayer(const gd::Layer& layer, std::size_t position) {
|
||||
layers.InsertLayer(layer, position);
|
||||
}
|
||||
|
||||
void Layout::RemoveLayer(const gd::String& name) {
|
||||
layers.RemoveLayer(name);
|
||||
}
|
||||
void Layout::RemoveLayer(const gd::String& name) { layers.RemoveLayer(name); }
|
||||
|
||||
void Layout::SwapLayers(std::size_t firstLayerIndex,
|
||||
std::size_t secondLayerIndex) {
|
||||
@@ -153,7 +152,7 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
allBehaviorsNames.push_back(behavior.GetName());
|
||||
}
|
||||
}
|
||||
auto &globalObjects = project.GetObjects();
|
||||
auto& globalObjects = project.GetObjects();
|
||||
for (std::size_t i = 0; i < globalObjects.GetObjectsCount(); ++i) {
|
||||
std::vector<gd::String> objectBehaviors =
|
||||
globalObjects.GetObject(i).GetAllBehaviorNames();
|
||||
@@ -173,7 +172,8 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
|
||||
if (behaviorsSharedData.find(name) != behaviorsSharedData.end()) continue;
|
||||
|
||||
auto sharedData = CreateBehaviorsSharedData(project, name, allBehaviorsTypes[i]);
|
||||
auto sharedData =
|
||||
CreateBehaviorsSharedData(project, name, allBehaviorsTypes[i]);
|
||||
if (sharedData) {
|
||||
behaviorsSharedData[name] = std::move(sharedData);
|
||||
}
|
||||
@@ -196,37 +196,39 @@ void Layout::UpdateBehaviorsSharedData(gd::Project& project) {
|
||||
}
|
||||
|
||||
std::unique_ptr<gd::BehaviorsSharedData> Layout::CreateBehaviorsSharedData(
|
||||
gd::Project& project, const gd::String& name, const gd::String& behaviorsType) {
|
||||
if (project.HasEventsBasedBehavior(behaviorsType)) {
|
||||
auto sharedData =
|
||||
gd::make_unique<gd::CustomBehaviorsSharedData>(name, project, behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::move(sharedData);
|
||||
}
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(
|
||||
project.GetCurrentPlatform(),
|
||||
behaviorsType);
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
gd::LogWarning("Tried to create a behavior shared data with an unknown type: " +
|
||||
behaviorsType + " on object " + GetName() + "!");
|
||||
gd::Project& project,
|
||||
const gd::String& name,
|
||||
const gd::String& behaviorsType) {
|
||||
if (project.HasEventsBasedBehavior(behaviorsType)) {
|
||||
auto sharedData = gd::make_unique<gd::CustomBehaviorsSharedData>(
|
||||
name, project, behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::move(sharedData);
|
||||
}
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
|
||||
behaviorsType);
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
gd::LogWarning(
|
||||
"Tried to create a behavior shared data with an unknown type: " +
|
||||
behaviorsType + " on object " + GetName() + "!");
|
||||
// It's probably an events-based behavior that was removed.
|
||||
// Create a custom behavior shared data to preserve the properties values.
|
||||
auto sharedData =
|
||||
gd::make_unique<gd::CustomBehaviorsSharedData>(name, project, behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::move(sharedData);
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* behaviorsSharedDataBluePrint =
|
||||
behaviorMetadata.GetSharedDataInstance();
|
||||
if (!behaviorsSharedDataBluePrint) return nullptr;
|
||||
|
||||
auto sharedData = behaviorsSharedDataBluePrint->Clone();
|
||||
sharedData->SetName(name);
|
||||
sharedData->SetTypeName(behaviorsType);
|
||||
auto sharedData = gd::make_unique<gd::CustomBehaviorsSharedData>(
|
||||
name, project, behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::unique_ptr<gd::BehaviorsSharedData>(sharedData);
|
||||
return std::move(sharedData);
|
||||
}
|
||||
|
||||
gd::BehaviorsSharedData* behaviorsSharedDataBluePrint =
|
||||
behaviorMetadata.GetSharedDataInstance();
|
||||
if (!behaviorsSharedDataBluePrint) return nullptr;
|
||||
|
||||
auto sharedData = behaviorsSharedDataBluePrint->Clone();
|
||||
sharedData->SetName(name);
|
||||
sharedData->SetTypeName(behaviorsType);
|
||||
sharedData->InitializeContent();
|
||||
return std::unique_ptr<gd::BehaviorsSharedData>(sharedData);
|
||||
}
|
||||
|
||||
void Layout::SerializeTo(SerializerElement& element) const {
|
||||
@@ -243,11 +245,13 @@ void Layout::SerializeTo(SerializerElement& element) const {
|
||||
|
||||
editorSettings.SerializeTo(element.AddChild("uiSettings"));
|
||||
|
||||
objectsContainer.GetObjectGroups().SerializeTo(element.AddChild("objectsGroups"));
|
||||
objectsContainer.GetObjectGroups().SerializeTo(
|
||||
element.AddChild("objectsGroups"));
|
||||
GetVariables().SerializeTo(element.AddChild("variables"));
|
||||
GetInitialInstances().SerializeTo(element.AddChild("instances"));
|
||||
objectsContainer.SerializeObjectsTo(element.AddChild("objects"));
|
||||
objectsContainer.SerializeFoldersTo(element.AddChild("objectsFolderStructure"));
|
||||
objectsContainer.SerializeFoldersTo(
|
||||
element.AddChild("objectsFolderStructure"));
|
||||
gd::EventsListSerialization::SerializeEventsTo(events,
|
||||
element.AddChild("events"));
|
||||
|
||||
@@ -257,15 +261,33 @@ void Layout::SerializeTo(SerializerElement& element) const {
|
||||
element.AddChild("behaviorsSharedData");
|
||||
behaviorDatasElement.ConsiderAsArrayOf("behaviorSharedData");
|
||||
for (const auto& it : behaviorsSharedData) {
|
||||
const gd::BehaviorsSharedData& sharedData = *it.second;
|
||||
SerializerElement& dataElement =
|
||||
behaviorDatasElement.AddChild("behaviorSharedData");
|
||||
|
||||
it.second->SerializeTo(dataElement);
|
||||
sharedData.SerializeTo(dataElement);
|
||||
dataElement.RemoveChild("type"); // The content can contain type or name
|
||||
// properties, remove them.
|
||||
dataElement.RemoveChild("name");
|
||||
dataElement.SetAttribute("type", it.second->GetTypeName());
|
||||
dataElement.SetAttribute("name", it.second->GetName());
|
||||
dataElement.SetAttribute("type", sharedData.GetTypeName());
|
||||
dataElement.SetAttribute("name", sharedData.GetName());
|
||||
|
||||
// Handle Quick Customization info.
|
||||
dataElement.RemoveChild("propertiesQuickCustomizationVisibilities");
|
||||
const QuickCustomizationVisibilitiesContainer&
|
||||
propertiesQuickCustomizationVisibilities =
|
||||
sharedData.GetPropertiesQuickCustomizationVisibilities();
|
||||
if (!propertiesQuickCustomizationVisibilities.IsEmpty()) {
|
||||
propertiesQuickCustomizationVisibilities.SerializeTo(
|
||||
dataElement.AddChild("propertiesQuickCustomizationVisibilities"));
|
||||
}
|
||||
const QuickCustomization::Visibility visibility =
|
||||
sharedData.GetQuickCustomizationVisibility();
|
||||
if (visibility != QuickCustomization::Visibility::Default) {
|
||||
dataElement.SetAttribute(
|
||||
"quickCustomizationVisibility",
|
||||
QuickCustomization::VisibilityAsString(visibility));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,9 +311,11 @@ void Layout::UnserializeFrom(gd::Project& project,
|
||||
gd::EventsListSerialization::UnserializeEventsFrom(
|
||||
project, GetEvents(), element.GetChild("events", 0, "Events"));
|
||||
|
||||
objectsContainer.UnserializeObjectsFrom(project, element.GetChild("objects", 0, "Objets"));
|
||||
objectsContainer.UnserializeObjectsFrom(
|
||||
project, element.GetChild("objects", 0, "Objets"));
|
||||
if (element.HasChild("objectsFolderStructure")) {
|
||||
objectsContainer.UnserializeFoldersFrom(project, element.GetChild("objectsFolderStructure", 0));
|
||||
objectsContainer.UnserializeFoldersFrom(
|
||||
project, element.GetChild("objectsFolderStructure", 0));
|
||||
}
|
||||
objectsContainer.AddMissingObjectsInRootFolder();
|
||||
|
||||
@@ -321,7 +345,6 @@ void Layout::UnserializeFrom(gd::Project& project,
|
||||
"Behavior"); // Compatibility with GD <= 4
|
||||
gd::String name = sharedDataElement.GetStringAttribute("name", "", "Name");
|
||||
|
||||
|
||||
auto sharedData = CreateBehaviorsSharedData(project, name, type);
|
||||
if (sharedData) {
|
||||
// Compatibility with GD <= 4.0.98
|
||||
@@ -336,6 +359,21 @@ void Layout::UnserializeFrom(gd::Project& project,
|
||||
else {
|
||||
sharedData->UnserializeFrom(sharedDataElement);
|
||||
}
|
||||
|
||||
// Handle Quick Customization info.
|
||||
if (sharedDataElement.HasChild(
|
||||
"propertiesQuickCustomizationVisibilities")) {
|
||||
sharedData->GetPropertiesQuickCustomizationVisibilities()
|
||||
.UnserializeFrom(sharedDataElement.GetChild(
|
||||
"propertiesQuickCustomizationVisibilities"));
|
||||
}
|
||||
if (sharedDataElement.HasChild("quickCustomizationVisibility")) {
|
||||
sharedData->SetQuickCustomizationVisibility(
|
||||
QuickCustomization::StringAsVisibility(
|
||||
sharedDataElement.GetStringAttribute(
|
||||
"quickCustomizationVisibility")));
|
||||
}
|
||||
|
||||
behaviorsSharedData[name] = std::move(sharedData);
|
||||
}
|
||||
}
|
||||
@@ -390,8 +428,9 @@ gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project,
|
||||
type = project.GetObject(name).GetType();
|
||||
|
||||
// Search in groups.
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
else if (searchInGroups) {
|
||||
for (std::size_t i = 0; i < layout.GetObjectGroups().size(); ++i) {
|
||||
if (layout.GetObjectGroups()[i].GetName() == name) {
|
||||
@@ -448,11 +487,12 @@ gd::String GD_CORE_API GetTypeOfObject(const gd::ObjectsContainer& project,
|
||||
return type;
|
||||
}
|
||||
|
||||
void GD_CORE_API FilterBehaviorNamesFromObject(
|
||||
const gd::Object &object, const gd::String &behaviorType,
|
||||
std::vector<gd::String> &behaviorNames) {
|
||||
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();) {
|
||||
auto &behaviorName = behaviorNames[i];
|
||||
auto& behaviorName = behaviorNames[i];
|
||||
if (!object.HasBehaviorNamed(behaviorName) ||
|
||||
object.GetBehavior(behaviorName).GetTypeName() != behaviorType) {
|
||||
behaviorNames.erase(behaviorNames.begin() + i);
|
||||
@@ -462,19 +502,21 @@ void GD_CORE_API FilterBehaviorNamesFromObject(
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
// Search in objects.
|
||||
if (layout.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = layout.GetObject(objectOrGroupName);
|
||||
auto& object = layout.GetObject(objectOrGroupName);
|
||||
auto behaviorNames = object.GetAllBehaviorNames();
|
||||
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
|
||||
return behaviorNames;
|
||||
}
|
||||
if (project.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = project.GetObject(objectOrGroupName);
|
||||
auto& object = project.GetObject(objectOrGroupName);
|
||||
auto behaviorNames = object.GetAllBehaviorNames();
|
||||
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
|
||||
return behaviorNames;
|
||||
@@ -486,9 +528,10 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
|
||||
}
|
||||
|
||||
// Search in groups.
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
const gd::ObjectsContainer *container;
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
const gd::ObjectsContainer* container;
|
||||
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
container = &layout;
|
||||
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
@@ -497,7 +540,7 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
|
||||
std::vector<gd::String> behaviorNames;
|
||||
return behaviorNames;
|
||||
}
|
||||
const vector<gd::String> &groupsObjects =
|
||||
const vector<gd::String>& groupsObjects =
|
||||
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
|
||||
|
||||
// Empty groups don't contain any behavior.
|
||||
@@ -510,15 +553,15 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
|
||||
auto behaviorNames = GetBehaviorNamesInObjectOrGroup(
|
||||
project, layout, groupsObjects[0], behaviorType, false);
|
||||
for (size_t i = 1; i < groupsObjects.size(); i++) {
|
||||
auto &objectName = groupsObjects[i];
|
||||
auto& objectName = groupsObjects[i];
|
||||
|
||||
if (layout.HasObjectNamed(objectName)) {
|
||||
auto &object = layout.GetObject(objectName);
|
||||
auto& object = layout.GetObject(objectName);
|
||||
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
|
||||
return behaviorNames;
|
||||
}
|
||||
if (project.HasObjectNamed(objectName)) {
|
||||
auto &object = project.GetObject(objectName);
|
||||
auto& object = project.GetObject(objectName);
|
||||
FilterBehaviorNamesFromObject(object, behaviorType, behaviorNames);
|
||||
return behaviorNames;
|
||||
}
|
||||
@@ -529,10 +572,10 @@ std::vector<gd::String> GD_CORE_API GetBehaviorNamesInObjectOrGroup(
|
||||
return behaviorNames;
|
||||
}
|
||||
|
||||
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) {
|
||||
// Search in objects.
|
||||
if (layout.HasObjectNamed(objectOrGroupName)) {
|
||||
@@ -547,9 +590,10 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
}
|
||||
|
||||
// Search in groups.
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
const gd::ObjectsContainer *container;
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
const gd::ObjectsContainer* container;
|
||||
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
container = &layout;
|
||||
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
@@ -557,7 +601,7 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
const vector<gd::String> &groupsObjects =
|
||||
const vector<gd::String>& groupsObjects =
|
||||
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
|
||||
|
||||
// Empty groups don't contain any behavior.
|
||||
@@ -566,9 +610,9 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
}
|
||||
|
||||
// Check that all objects have the behavior.
|
||||
for (auto &&object : groupsObjects) {
|
||||
if (!HasBehaviorInObjectOrGroup(project, layout, object, behaviorName,
|
||||
false)) {
|
||||
for (auto&& object : groupsObjects) {
|
||||
if (!HasBehaviorInObjectOrGroup(
|
||||
project, layout, object, behaviorName, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -576,18 +620,18 @@ bool GD_CORE_API HasBehaviorInObjectOrGroup(const gd::ObjectsContainer &project,
|
||||
}
|
||||
|
||||
bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::String objectOrGroupName,
|
||||
gd::String behaviorName,
|
||||
bool searchInGroups) {
|
||||
const gd::ObjectsContainer& layout,
|
||||
gd::String objectOrGroupName,
|
||||
gd::String behaviorName,
|
||||
bool searchInGroups) {
|
||||
// Search in objects.
|
||||
if (layout.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = layout.GetObject(objectOrGroupName);
|
||||
auto& object = layout.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName) &&
|
||||
object.GetBehavior(behaviorName).IsDefaultBehavior();
|
||||
}
|
||||
if (project.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = project.GetObject(objectOrGroupName);
|
||||
auto& object = project.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName) &&
|
||||
object.GetBehavior(behaviorName).IsDefaultBehavior();
|
||||
}
|
||||
@@ -597,9 +641,10 @@ bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
|
||||
}
|
||||
|
||||
// Search in groups.
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
const gd::ObjectsContainer *container;
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
const gd::ObjectsContainer* container;
|
||||
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
container = &layout;
|
||||
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
@@ -607,7 +652,7 @@ bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
const vector<gd::String> &groupsObjects =
|
||||
const vector<gd::String>& groupsObjects =
|
||||
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
|
||||
|
||||
// Empty groups don't contain any behavior.
|
||||
@@ -616,30 +661,32 @@ bool GD_CORE_API IsDefaultBehavior(const gd::ObjectsContainer& project,
|
||||
}
|
||||
|
||||
// Check that all objects have the same type.
|
||||
for (auto &&object : groupsObjects) {
|
||||
if (!IsDefaultBehavior(project, layout, object, behaviorName,
|
||||
false)) {
|
||||
for (auto&& object : groupsObjects) {
|
||||
if (!IsDefaultBehavior(project, layout, object, behaviorName, false)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return 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) {
|
||||
gd::String GD_CORE_API
|
||||
GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContainer& project,
|
||||
const gd::ObjectsContainer& layout,
|
||||
const gd::String& objectOrGroupName,
|
||||
const gd::String& behaviorName,
|
||||
bool searchInGroups) {
|
||||
// Search in objects.
|
||||
if (layout.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = layout.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName) ?
|
||||
object.GetBehavior(behaviorName).GetTypeName() : "";
|
||||
auto& object = layout.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName)
|
||||
? object.GetBehavior(behaviorName).GetTypeName()
|
||||
: "";
|
||||
}
|
||||
if (project.HasObjectNamed(objectOrGroupName)) {
|
||||
auto &object = project.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName) ?
|
||||
object.GetBehavior(behaviorName).GetTypeName() : "";
|
||||
auto& object = project.GetObject(objectOrGroupName);
|
||||
return object.HasBehaviorNamed(behaviorName)
|
||||
? object.GetBehavior(behaviorName).GetTypeName()
|
||||
: "";
|
||||
}
|
||||
|
||||
if (!searchInGroups) {
|
||||
@@ -647,9 +694,10 @@ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContain
|
||||
}
|
||||
|
||||
// Search in groups.
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
const gd::ObjectsContainer *container;
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
const gd::ObjectsContainer* container;
|
||||
if (layout.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
container = &layout;
|
||||
} else if (project.GetObjectGroups().Has(objectOrGroupName)) {
|
||||
@@ -657,7 +705,7 @@ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContain
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
const vector<gd::String> &groupsObjects =
|
||||
const vector<gd::String>& groupsObjects =
|
||||
container->GetObjectGroups().Get(objectOrGroupName).GetAllObjectsNames();
|
||||
|
||||
// Empty groups don't contain any behavior.
|
||||
@@ -668,9 +716,9 @@ gd::String GD_CORE_API GetTypeOfBehaviorInObjectOrGroup(const gd::ObjectsContain
|
||||
// Check that all objects have the behavior with the same type.
|
||||
auto behaviorType = GetTypeOfBehaviorInObjectOrGroup(
|
||||
project, layout, groupsObjects[0], behaviorName, false);
|
||||
for (auto &&object : groupsObjects) {
|
||||
if (GetTypeOfBehaviorInObjectOrGroup(project, layout, object, behaviorName,
|
||||
false) != behaviorType) {
|
||||
for (auto&& object : groupsObjects) {
|
||||
if (GetTypeOfBehaviorInObjectOrGroup(
|
||||
project, layout, object, behaviorName, false) != behaviorType) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -682,14 +730,14 @@ gd::String GD_CORE_API GetTypeOfBehavior(const gd::ObjectsContainer& project,
|
||||
gd::String name,
|
||||
bool searchInGroups) {
|
||||
for (std::size_t i = 0; i < layout.GetObjectsCount(); ++i) {
|
||||
const auto &object = layout.GetObject(i);
|
||||
const auto& object = layout.GetObject(i);
|
||||
if (object.HasBehaviorNamed(name)) {
|
||||
return object.GetBehavior(name).GetTypeName();
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < project.GetObjectsCount(); ++i) {
|
||||
const auto &object = project.GetObject(i);
|
||||
const auto& object = project.GetObject(i);
|
||||
if (object.HasBehaviorNamed(name)) {
|
||||
return object.GetBehavior(name).GetTypeName();
|
||||
}
|
||||
@@ -726,8 +774,9 @@ GetBehaviorsOfObject(const gd::ObjectsContainer& project,
|
||||
}
|
||||
|
||||
// Search in groups
|
||||
// Currently, a group is considered as the "intersection" of all of its objects.
|
||||
// Search "groups is the intersection of its objects" in the codebase.
|
||||
// Currently, a group is considered as the "intersection" of all of its
|
||||
// objects. Search "groups is the intersection of its objects" in the
|
||||
// codebase.
|
||||
if (searchInGroups) {
|
||||
for (std::size_t i = 0; i < layout.GetObjectGroups().size(); ++i) {
|
||||
if (layout.GetObjectGroups()[i].GetName() == name) {
|
||||
|
@@ -369,9 +369,9 @@ class GD_CORE_API Layout {
|
||||
private:
|
||||
gd::String name; ///< Scene name
|
||||
gd::String mangledName; ///< The scene name mangled by SceneNameMangler
|
||||
unsigned int backgroundColorR; ///< Background color Red component
|
||||
unsigned int backgroundColorG; ///< Background color Green component
|
||||
unsigned int backgroundColorB; ///< Background color Blue component
|
||||
unsigned int backgroundColorR = 0; ///< Background color Red component
|
||||
unsigned int backgroundColorG = 0; ///< Background color Green component
|
||||
unsigned int backgroundColorB = 0; ///< Background color Blue component
|
||||
gd::String title; ///< Title displayed in the window
|
||||
gd::VariablesContainer variables; ///< Variables list
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
@@ -379,12 +379,12 @@ class GD_CORE_API Layout {
|
||||
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
|
||||
///< startup.
|
||||
bool standardSortMethod; ///< True to sort objects using standard sort.
|
||||
bool disableInputWhenNotFocused; /// If set to true, the input must be
|
||||
/// disabled when the window do not have the
|
||||
/// focus.
|
||||
bool stopSoundsOnStartup = true; ///< True to make the scene stop all sounds at
|
||||
///< startup.
|
||||
bool standardSortMethod = true; ///< True to sort objects using standard sort.
|
||||
bool disableInputWhenNotFocused = true; /// If set to true, the input must be
|
||||
/// disabled when the window do not have the
|
||||
/// focus.
|
||||
static gd::BehaviorsSharedData
|
||||
badBehaviorSharedData; ///< Null object, returned when
|
||||
///< GetBehaviorSharedData can not find the
|
||||
@@ -405,18 +405,6 @@ class GD_CORE_API Layout {
|
||||
const gd::String& behaviorsType);
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Functor testing layout name.
|
||||
* \see gd::Layout
|
||||
*/
|
||||
struct LayoutHasName
|
||||
: public std::binary_function<std::unique_ptr<Layout>, gd::String, bool> {
|
||||
bool operator()(const std::unique_ptr<Layout>& layout,
|
||||
gd::String name) const {
|
||||
return layout->GetName() == name;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get the names of all layers from the given layout
|
||||
* that are invisible.
|
||||
|
@@ -12,8 +12,9 @@
|
||||
#include "GDCore/Project/CustomBehavior.h"
|
||||
#include "GDCore/Project/Layout.h"
|
||||
#include "GDCore/Project/Project.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Project/PropertyDescriptor.h"
|
||||
#include "GDCore/Project/QuickCustomization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/Tools/Log.h"
|
||||
#include "GDCore/Tools/UUID/UUID.h"
|
||||
|
||||
@@ -27,8 +28,8 @@ Object::Object(const gd::String& name_,
|
||||
: name(name_),
|
||||
configuration(std::move(configuration_)),
|
||||
objectVariables(gd::VariablesContainer::SourceType::Object) {
|
||||
SetType(type_);
|
||||
}
|
||||
SetType(type_);
|
||||
}
|
||||
|
||||
Object::Object(const gd::String& name_,
|
||||
const gd::String& type_,
|
||||
@@ -36,8 +37,8 @@ Object::Object(const gd::String& name_,
|
||||
: name(name_),
|
||||
configuration(configuration_),
|
||||
objectVariables(gd::VariablesContainer::SourceType::Object) {
|
||||
SetType(type_);
|
||||
}
|
||||
SetType(type_);
|
||||
}
|
||||
|
||||
void Object::Init(const gd::Object& object) {
|
||||
persistentUuid = object.persistentUuid;
|
||||
@@ -54,9 +55,7 @@ void Object::Init(const gd::Object& object) {
|
||||
configuration = object.configuration->Clone();
|
||||
}
|
||||
|
||||
gd::ObjectConfiguration& Object::GetConfiguration() {
|
||||
return *configuration;
|
||||
}
|
||||
gd::ObjectConfiguration& Object::GetConfiguration() { return *configuration; }
|
||||
|
||||
const gd::ObjectConfiguration& Object::GetConfiguration() const {
|
||||
return *configuration;
|
||||
@@ -77,8 +76,7 @@ bool Object::RenameBehavior(const gd::String& name, const gd::String& newName) {
|
||||
behaviors.find(newName) != behaviors.end())
|
||||
return false;
|
||||
|
||||
std::unique_ptr<Behavior> aut =
|
||||
std::move(behaviors.find(name)->second);
|
||||
std::unique_ptr<Behavior> aut = std::move(behaviors.find(name)->second);
|
||||
behaviors.erase(name);
|
||||
behaviors[newName] = std::move(aut);
|
||||
behaviors[newName]->SetName(newName);
|
||||
@@ -99,10 +97,10 @@ bool Object::HasBehaviorNamed(const gd::String& name) const {
|
||||
}
|
||||
|
||||
gd::Behavior* Object::AddNewBehavior(const gd::Project& project,
|
||||
const gd::String& type,
|
||||
const gd::String& name) {
|
||||
auto initializeAndAdd =
|
||||
[this, &name](std::unique_ptr<gd::Behavior> behavior) {
|
||||
const gd::String& type,
|
||||
const gd::String& name) {
|
||||
auto initializeAndAdd = [this,
|
||||
&name](std::unique_ptr<gd::Behavior> behavior) {
|
||||
behavior->InitializeContent();
|
||||
this->behaviors[name] = std::move(behavior);
|
||||
return this->behaviors[name].get();
|
||||
@@ -111,18 +109,17 @@ gd::Behavior* Object::AddNewBehavior(const gd::Project& project,
|
||||
if (project.HasEventsBasedBehavior(type)) {
|
||||
return initializeAndAdd(
|
||||
gd::make_unique<CustomBehavior>(name, project, type));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
const gd::BehaviorMetadata& behaviorMetadata =
|
||||
gd::MetadataProvider::GetBehaviorMetadata(project.GetCurrentPlatform(),
|
||||
type);
|
||||
if (gd::MetadataProvider::IsBadBehaviorMetadata(behaviorMetadata)) {
|
||||
gd::LogWarning("Tried to create a behavior with an unknown type: " + type
|
||||
+ " on object " + GetName() + "!");
|
||||
// It's probably an events-based behavior that was removed.
|
||||
// Create a custom behavior to preserve the properties values.
|
||||
return initializeAndAdd(
|
||||
gd::make_unique<CustomBehavior>(name, project, type));
|
||||
gd::LogWarning("Tried to create a behavior with an unknown type: " +
|
||||
type + " on object " + GetName() + "!");
|
||||
// It's probably an events-based behavior that was removed.
|
||||
// Create a custom behavior to preserve the properties values.
|
||||
return initializeAndAdd(
|
||||
gd::make_unique<CustomBehavior>(name, project, type));
|
||||
}
|
||||
std::unique_ptr<gd::Behavior> behavior(behaviorMetadata.Get().Clone());
|
||||
behavior->SetName(name);
|
||||
@@ -196,6 +193,23 @@ void Object::UnserializeFrom(gd::Project& project,
|
||||
else {
|
||||
behavior->UnserializeFrom(behaviorElement);
|
||||
}
|
||||
|
||||
bool isFolded = behaviorElement.GetBoolAttribute("isFolded", false);
|
||||
behavior->SetFolded(isFolded);
|
||||
|
||||
// Handle Quick Customization info.
|
||||
if (behaviorElement.HasChild(
|
||||
"propertiesQuickCustomizationVisibilities")) {
|
||||
behavior->GetPropertiesQuickCustomizationVisibilities().UnserializeFrom(
|
||||
behaviorElement.GetChild(
|
||||
"propertiesQuickCustomizationVisibilities"));
|
||||
}
|
||||
if (behaviorElement.HasChild("quickCustomizationVisibility")) {
|
||||
behavior->SetQuickCustomizationVisibility(
|
||||
QuickCustomization::StringAsVisibility(
|
||||
behaviorElement.GetStringAttribute(
|
||||
"quickCustomizationVisibility")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,8 +231,8 @@ void Object::SerializeTo(SerializerElement& element) const {
|
||||
std::vector<gd::String> allBehaviors = GetAllBehaviorNames();
|
||||
for (std::size_t i = 0; i < allBehaviors.size(); ++i) {
|
||||
const gd::Behavior& behavior = GetBehavior(allBehaviors[i]);
|
||||
// Default behaviors are added at the object creation according to metadata.
|
||||
// They don't need to be serialized.
|
||||
// Default behaviors are added at the object creation according to
|
||||
// metadata. They don't need to be serialized.
|
||||
if (behavior.IsDefaultBehavior()) {
|
||||
continue;
|
||||
}
|
||||
@@ -228,8 +242,27 @@ void Object::SerializeTo(SerializerElement& element) const {
|
||||
behaviorElement.RemoveChild("type"); // The content can contain type or
|
||||
// name properties, remove them.
|
||||
behaviorElement.RemoveChild("name");
|
||||
behaviorElement.RemoveChild("isFolded");
|
||||
behaviorElement.SetAttribute("type", behavior.GetTypeName());
|
||||
behaviorElement.SetAttribute("name", behavior.GetName());
|
||||
if (behavior.IsFolded()) behaviorElement.SetAttribute("isFolded", true);
|
||||
|
||||
// Handle Quick Customization info.
|
||||
behaviorElement.RemoveChild("propertiesQuickCustomizationVisibilities");
|
||||
const QuickCustomizationVisibilitiesContainer&
|
||||
propertiesQuickCustomizationVisibilities =
|
||||
behavior.GetPropertiesQuickCustomizationVisibilities();
|
||||
if (!propertiesQuickCustomizationVisibilities.IsEmpty()) {
|
||||
propertiesQuickCustomizationVisibilities.SerializeTo(
|
||||
behaviorElement.AddChild("propertiesQuickCustomizationVisibilities"));
|
||||
}
|
||||
const QuickCustomization::Visibility visibility =
|
||||
behavior.GetQuickCustomizationVisibility();
|
||||
if (visibility != QuickCustomization::Visibility::Default) {
|
||||
behaviorElement.SetAttribute(
|
||||
"quickCustomizationVisibility",
|
||||
QuickCustomization::VisibilityAsString(visibility));
|
||||
}
|
||||
}
|
||||
|
||||
configuration->SerializeTo(element);
|
||||
|
@@ -193,7 +193,7 @@ class GD_CORE_API ObjectFolderOrObject {
|
||||
static gd::ObjectFolderOrObject badObjectFolderOrObject;
|
||||
|
||||
gd::ObjectFolderOrObject*
|
||||
parent; // nullptr if root folder, points to the parent folder otherwise.
|
||||
parent = nullptr; // nullptr if root folder, points to the parent folder otherwise.
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
|
||||
// Representing an object:
|
||||
|
@@ -71,7 +71,7 @@ Project::Project()
|
||||
isPlayableWithKeyboard(false),
|
||||
isPlayableWithGamepad(false),
|
||||
isPlayableWithMobile(false),
|
||||
currentPlatform(NULL),
|
||||
currentPlatform(nullptr),
|
||||
gdMajorVersion(gd::VersionWrapper::Major()),
|
||||
gdMinorVersion(gd::VersionWrapper::Minor()),
|
||||
gdBuildVersion(gd::VersionWrapper::Build()),
|
||||
@@ -264,15 +264,21 @@ bool Project::RemovePlatform(const gd::String& platformName) {
|
||||
bool Project::HasLayoutNamed(const gd::String& name) const {
|
||||
return (find_if(scenes.begin(),
|
||||
scenes.end(),
|
||||
bind2nd(gd::LayoutHasName(), name)) != scenes.end());
|
||||
[&name](const std::unique_ptr<gd::Layout>& layout) {
|
||||
return layout->GetName() == name;
|
||||
}) != scenes.end());
|
||||
}
|
||||
gd::Layout& Project::GetLayout(const gd::String& name) {
|
||||
return *(*find_if(
|
||||
scenes.begin(), scenes.end(), bind2nd(gd::LayoutHasName(), name)));
|
||||
scenes.begin(), scenes.end(), [&name](const std::unique_ptr<gd::Layout>& layout) {
|
||||
return layout->GetName() == name;
|
||||
}));
|
||||
}
|
||||
const gd::Layout& Project::GetLayout(const gd::String& name) const {
|
||||
return *(*find_if(
|
||||
scenes.begin(), scenes.end(), bind2nd(gd::LayoutHasName(), name)));
|
||||
scenes.begin(), scenes.end(), [&name](const std::unique_ptr<gd::Layout>& layout) {
|
||||
return layout->GetName() == name;
|
||||
}));
|
||||
}
|
||||
gd::Layout& Project::GetLayout(std::size_t index) { return *scenes[index]; }
|
||||
const gd::Layout& Project::GetLayout(std::size_t index) const {
|
||||
@@ -317,7 +323,9 @@ gd::Layout& Project::InsertLayout(const gd::Layout& layout,
|
||||
|
||||
void Project::RemoveLayout(const gd::String& name) {
|
||||
std::vector<std::unique_ptr<gd::Layout> >::iterator scene =
|
||||
find_if(scenes.begin(), scenes.end(), bind2nd(gd::LayoutHasName(), name));
|
||||
find_if(scenes.begin(), scenes.end(), [&name](const std::unique_ptr<gd::Layout>& layout) {
|
||||
return layout->GetName() == name;
|
||||
});
|
||||
if (scene == scenes.end()) return;
|
||||
|
||||
scenes.erase(scene);
|
||||
@@ -326,19 +334,24 @@ void Project::RemoveLayout(const gd::String& name) {
|
||||
bool Project::HasExternalEventsNamed(const gd::String& name) const {
|
||||
return (find_if(externalEvents.begin(),
|
||||
externalEvents.end(),
|
||||
bind2nd(gd::ExternalEventsHasName(), name)) !=
|
||||
externalEvents.end());
|
||||
[&name](const std::unique_ptr<gd::ExternalEvents>& externalEvents) {
|
||||
return externalEvents->GetName() == name;
|
||||
}) != externalEvents.end());
|
||||
}
|
||||
gd::ExternalEvents& Project::GetExternalEvents(const gd::String& name) {
|
||||
return *(*find_if(externalEvents.begin(),
|
||||
externalEvents.end(),
|
||||
bind2nd(gd::ExternalEventsHasName(), name)));
|
||||
[&name](const std::unique_ptr<gd::ExternalEvents>& externalEvents) {
|
||||
return externalEvents->GetName() == name;
|
||||
}));
|
||||
}
|
||||
const gd::ExternalEvents& Project::GetExternalEvents(
|
||||
const gd::String& name) const {
|
||||
return *(*find_if(externalEvents.begin(),
|
||||
externalEvents.end(),
|
||||
bind2nd(gd::ExternalEventsHasName(), name)));
|
||||
[&name](const std::unique_ptr<gd::ExternalEvents>& externalEvents) {
|
||||
return externalEvents->GetName() == name;
|
||||
}));
|
||||
}
|
||||
gd::ExternalEvents& Project::GetExternalEvents(std::size_t index) {
|
||||
return *externalEvents[index];
|
||||
@@ -382,7 +395,9 @@ void Project::RemoveExternalEvents(const gd::String& name) {
|
||||
std::vector<std::unique_ptr<gd::ExternalEvents> >::iterator events =
|
||||
find_if(externalEvents.begin(),
|
||||
externalEvents.end(),
|
||||
bind2nd(gd::ExternalEventsHasName(), name));
|
||||
[&name](const std::unique_ptr<gd::ExternalEvents>& externalEvents) {
|
||||
return externalEvents->GetName() == name;
|
||||
});
|
||||
if (events == externalEvents.end()) return;
|
||||
|
||||
externalEvents.erase(events);
|
||||
@@ -448,19 +463,24 @@ void Project::SwapExternalLayouts(std::size_t first, std::size_t second) {
|
||||
bool Project::HasExternalLayoutNamed(const gd::String& name) const {
|
||||
return (find_if(externalLayouts.begin(),
|
||||
externalLayouts.end(),
|
||||
bind2nd(gd::ExternalLayoutHasName(), name)) !=
|
||||
externalLayouts.end());
|
||||
[&name](const std::unique_ptr<gd::ExternalLayout>& externalLayout) {
|
||||
return externalLayout->GetName() == name;
|
||||
}) != externalLayouts.end());
|
||||
}
|
||||
gd::ExternalLayout& Project::GetExternalLayout(const gd::String& name) {
|
||||
return *(*find_if(externalLayouts.begin(),
|
||||
externalLayouts.end(),
|
||||
bind2nd(gd::ExternalLayoutHasName(), name)));
|
||||
[&name](const std::unique_ptr<gd::ExternalLayout>& externalLayout) {
|
||||
return externalLayout->GetName() == name;
|
||||
}));
|
||||
}
|
||||
const gd::ExternalLayout& Project::GetExternalLayout(
|
||||
const gd::String& name) const {
|
||||
return *(*find_if(externalLayouts.begin(),
|
||||
externalLayouts.end(),
|
||||
bind2nd(gd::ExternalLayoutHasName(), name)));
|
||||
[&name](const std::unique_ptr<gd::ExternalLayout>& externalLayout) {
|
||||
return externalLayout->GetName() == name;
|
||||
}));
|
||||
}
|
||||
gd::ExternalLayout& Project::GetExternalLayout(std::size_t index) {
|
||||
return *externalLayouts[index];
|
||||
@@ -504,7 +524,9 @@ void Project::RemoveExternalLayout(const gd::String& name) {
|
||||
std::vector<std::unique_ptr<gd::ExternalLayout> >::iterator externalLayout =
|
||||
find_if(externalLayouts.begin(),
|
||||
externalLayouts.end(),
|
||||
bind2nd(gd::ExternalLayoutHasName(), name));
|
||||
[&name](const std::unique_ptr<gd::ExternalLayout>& externalLayout) {
|
||||
return externalLayout->GetName() == name;
|
||||
});
|
||||
if (externalLayout == externalLayouts.end()) return;
|
||||
|
||||
externalLayouts.erase(externalLayout);
|
||||
@@ -1076,7 +1098,9 @@ bool Project::HasSourceFile(gd::String name, gd::String language) const {
|
||||
vector<std::unique_ptr<SourceFile> >::const_iterator sourceFile =
|
||||
find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
bind2nd(gd::ExternalSourceFileHasName(), name));
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
});
|
||||
|
||||
if (sourceFile == externalSourceFiles.end()) return false;
|
||||
|
||||
@@ -1086,20 +1110,26 @@ bool Project::HasSourceFile(gd::String name, gd::String language) const {
|
||||
gd::SourceFile& Project::GetSourceFile(const gd::String& name) {
|
||||
return *(*find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
bind2nd(gd::ExternalSourceFileHasName(), name)));
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
}));
|
||||
}
|
||||
|
||||
const gd::SourceFile& Project::GetSourceFile(const gd::String& name) const {
|
||||
return *(*find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
bind2nd(gd::ExternalSourceFileHasName(), name)));
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
}));
|
||||
}
|
||||
|
||||
void Project::RemoveSourceFile(const gd::String& name) {
|
||||
std::vector<std::unique_ptr<gd::SourceFile> >::iterator sourceFile =
|
||||
find_if(externalSourceFiles.begin(),
|
||||
externalSourceFiles.end(),
|
||||
bind2nd(gd::ExternalSourceFileHasName(), name));
|
||||
[&name](const std::unique_ptr<SourceFile>& sourceFile) {
|
||||
return sourceFile->GetFileName() == name;
|
||||
});
|
||||
if (sourceFile == externalSourceFiles.end()) return;
|
||||
|
||||
externalSourceFiles.erase(sourceFile);
|
||||
|
@@ -990,16 +990,12 @@ class GD_CORE_API Project {
|
||||
/**
|
||||
* \brief return the objects of the project.
|
||||
*/
|
||||
gd::ObjectsContainer& GetObjects() {
|
||||
return objectsContainer;
|
||||
}
|
||||
gd::ObjectsContainer& GetObjects() { return objectsContainer; }
|
||||
|
||||
/**
|
||||
* \brief Return the objects of the project.
|
||||
*/
|
||||
const gd::ObjectsContainer& GetObjects() const {
|
||||
return objectsContainer;
|
||||
}
|
||||
const gd::ObjectsContainer& GetObjects() const { return objectsContainer; }
|
||||
///@}
|
||||
|
||||
/** \name Identifier names
|
||||
@@ -1080,32 +1076,35 @@ class GD_CORE_API Project {
|
||||
*/
|
||||
void Init(const gd::Project& project);
|
||||
|
||||
gd::String name; ///< Game name
|
||||
gd::String description; ///< Game description
|
||||
gd::String version; ///< Game version number (used for some exports)
|
||||
unsigned int windowWidth; ///< Window default width
|
||||
unsigned int windowHeight; ///< Window default height
|
||||
int maxFPS; ///< Maximum Frame Per Seconds, -1 for unlimited
|
||||
unsigned int minFPS; ///< Minimum Frame Per Seconds ( slow down game if FPS
|
||||
///< are below this number )
|
||||
bool verticalSync; ///< If true, must activate vertical synchronization.
|
||||
gd::String name; ///< Game name
|
||||
gd::String description; ///< Game description
|
||||
gd::String version; ///< Game version number (used for some exports)
|
||||
unsigned int windowWidth = 0; ///< Window default width
|
||||
unsigned int windowHeight = 0; ///< Window default height
|
||||
int maxFPS = 0; ///< Maximum Frame Per Seconds, -1 for unlimited
|
||||
unsigned int minFPS = 0; ///< Minimum Frame Per Seconds ( slow down game if
|
||||
///< FPS are below this number )
|
||||
bool verticalSync =
|
||||
false; ///< If true, must activate vertical synchronization.
|
||||
gd::String scaleMode;
|
||||
bool pixelsRounding; ///< If true, the rendering should stop pixel
|
||||
///< interpolation of rendered objects.
|
||||
bool adaptGameResolutionAtRuntime; ///< Should the game resolution be adapted
|
||||
///< to the window size at runtime
|
||||
bool pixelsRounding = false; ///< If true, the rendering should stop pixel
|
||||
///< interpolation of rendered objects.
|
||||
bool adaptGameResolutionAtRuntime =
|
||||
true; ///< Should the game resolution be adapted
|
||||
///< to the window size at runtime
|
||||
gd::String
|
||||
sizeOnStartupMode; ///< How to adapt the game size to the screen. Can be
|
||||
///< "adaptWidth", "adaptHeight" or empty
|
||||
gd::String antialiasingMode;
|
||||
bool isAntialisingEnabledOnMobile;
|
||||
bool isAntialisingEnabledOnMobile = false;
|
||||
gd::String projectUuid; ///< UUID useful to identify the game in online
|
||||
///< services or database that would require it.
|
||||
bool useDeprecatedZeroAsDefaultZOrder; ///< If true, objects created from
|
||||
///< events will have 0 as Z order,
|
||||
///< instead of the highest Z order
|
||||
///< found on the layer at the scene
|
||||
///< startup.
|
||||
bool useDeprecatedZeroAsDefaultZOrder =
|
||||
false; ///< If true, objects created from
|
||||
///< events will have 0 as Z order,
|
||||
///< instead of the highest Z order
|
||||
///< found on the layer at the scene
|
||||
///< startup.
|
||||
std::vector<std::unique_ptr<gd::Layout> > scenes; ///< List of all scenes
|
||||
gd::VariablesContainer variables; ///< Initial global variables
|
||||
gd::ObjectsContainer objectsContainer;
|
||||
@@ -1118,7 +1117,8 @@ class GD_CORE_API Project {
|
||||
std::vector<gd::Platform*>
|
||||
platforms; ///< Pointers to the platforms this project supports.
|
||||
gd::String firstLayout;
|
||||
bool useExternalSourceFiles; ///< True if game used external source files.
|
||||
bool useExternalSourceFiles =
|
||||
false; ///< True if game used external source files.
|
||||
std::vector<std::unique_ptr<gd::SourceFile> >
|
||||
externalSourceFiles; ///< List of external source files used.
|
||||
gd::String author; ///< Game author name, for publishing purpose.
|
||||
@@ -1127,35 +1127,40 @@ class GD_CORE_API Project {
|
||||
std::vector<gd::String>
|
||||
authorUsernames; ///< Game author usernames, from GDevelop users DB.
|
||||
std::vector<gd::String> categories; ///< Game categories
|
||||
bool isPlayableWithKeyboard; ///< The project is playable with a keyboard.
|
||||
bool isPlayableWithGamepad; ///< The project is playable with a gamepad.
|
||||
bool isPlayableWithMobile; ///< The project is playable on a mobile.
|
||||
gd::String packageName; ///< Game package name
|
||||
bool isPlayableWithKeyboard =
|
||||
false; ///< The project is playable with a keyboard.
|
||||
bool isPlayableWithGamepad =
|
||||
false; ///< The project is playable with a gamepad.
|
||||
bool isPlayableWithMobile = false; ///< The project is playable on a mobile.
|
||||
gd::String packageName; ///< Game package name
|
||||
gd::String templateSlug; ///< The slug of the template from which the game is
|
||||
///< created.
|
||||
gd::String orientation; ///< Lock game orientation (on mobile devices).
|
||||
///< "default", "landscape" or "portrait".
|
||||
bool
|
||||
folderProject; ///< True if folder project, false if single file project.
|
||||
bool folderProject =
|
||||
false; ///< True if folder project, false if single file project.
|
||||
gd::String
|
||||
projectFile; ///< Path to the project file - when editing a local file.
|
||||
gd::String latestCompilationDirectory;
|
||||
gd::Platform*
|
||||
currentPlatform; ///< The platform being used to edit the project.
|
||||
gd::Platform* currentPlatform =
|
||||
nullptr; ///< The platform being used to edit the project.
|
||||
gd::PlatformSpecificAssets platformSpecificAssets;
|
||||
gd::LoadingScreen loadingScreen;
|
||||
gd::Watermark watermark;
|
||||
std::vector<std::unique_ptr<gd::ExternalEvents> >
|
||||
externalEvents; ///< List of all externals events
|
||||
ExtensionProperties
|
||||
extensionProperties; ///< The properties of the extensions.
|
||||
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
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdBuildVersion; ///< The GD build version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdMajorVersion =
|
||||
0; ///< The GD major version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdMinorVersion =
|
||||
0; ///< The GD minor version used the last
|
||||
///< time the project was saved.
|
||||
mutable unsigned int gdBuildVersion =
|
||||
0; ///< The GD build version used the last
|
||||
///< time the project was saved.
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
@@ -33,6 +33,7 @@ class GD_CORE_API PropertyDescriptor {
|
||||
PropertyDescriptor(gd::String propertyValue)
|
||||
: currentValue(propertyValue), type("string"), label(""), hidden(false),
|
||||
deprecated(false), advanced(false),
|
||||
hasImpactOnOtherProperties(false),
|
||||
measurementUnit(gd::MeasurementUnit::GetUndefined()),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default) {}
|
||||
|
||||
@@ -41,6 +42,7 @@ class GD_CORE_API PropertyDescriptor {
|
||||
*/
|
||||
PropertyDescriptor()
|
||||
: hidden(false), deprecated(false), advanced(false),
|
||||
hasImpactOnOtherProperties(false),
|
||||
measurementUnit(gd::MeasurementUnit::GetUndefined()),
|
||||
quickCustomizationVisibility(QuickCustomization::Visibility::Default){};
|
||||
|
||||
@@ -175,6 +177,21 @@ class GD_CORE_API PropertyDescriptor {
|
||||
*/
|
||||
bool IsAdvanced() const { return advanced; }
|
||||
|
||||
/**
|
||||
* \brief Check if the property has impact on other properties - which means a change
|
||||
* must re-render other properties.
|
||||
*/
|
||||
bool HasImpactOnOtherProperties() const { return hasImpactOnOtherProperties; }
|
||||
|
||||
/**
|
||||
* \brief Set if the property has impact on other properties - which means a change
|
||||
* must re-render other properties.
|
||||
*/
|
||||
PropertyDescriptor& SetHasImpactOnOtherProperties(bool enable) {
|
||||
hasImpactOnOtherProperties = enable;
|
||||
return *this;
|
||||
}
|
||||
|
||||
QuickCustomization::Visibility GetQuickCustomizationVisibility() const { return quickCustomizationVisibility; }
|
||||
|
||||
PropertyDescriptor& SetQuickCustomizationVisibility(QuickCustomization::Visibility visibility) {
|
||||
@@ -221,6 +238,7 @@ class GD_CORE_API PropertyDescriptor {
|
||||
bool hidden;
|
||||
bool deprecated;
|
||||
bool advanced;
|
||||
bool hasImpactOnOtherProperties;
|
||||
gd::MeasurementUnit measurementUnit; //< The unit of measurement of the property vale.
|
||||
QuickCustomization::Visibility quickCustomizationVisibility;
|
||||
};
|
||||
|
@@ -1,16 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
class QuickCustomization {
|
||||
public:
|
||||
enum Visibility {
|
||||
/** Visibility based on the parent or editor heuristics (probably visible). */
|
||||
/** Visibility based on the parent or editor heuristics (probably visible).
|
||||
*/
|
||||
Default,
|
||||
/** Visible in the quick customization editor. */
|
||||
Visible,
|
||||
/** Not visible in the quick customization editor. */
|
||||
Hidden
|
||||
};
|
||||
|
||||
static Visibility StringAsVisibility(const gd::String& str) {
|
||||
if (str == "visible")
|
||||
return Visibility::Visible;
|
||||
else if (str == "hidden")
|
||||
return Visibility::Hidden;
|
||||
|
||||
return Visibility::Default;
|
||||
}
|
||||
|
||||
static gd::String VisibilityAsString(Visibility visibility) {
|
||||
if (visibility == Visibility::Visible)
|
||||
return "visible";
|
||||
else if (visibility == Visibility::Hidden)
|
||||
return "hidden";
|
||||
|
||||
return "default";
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* GDevelop Core
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include "GDCore/Project/QuickCustomizationVisibilitiesContainer.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include "GDCore/Project/QuickCustomization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/UUID/UUID.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace gd {
|
||||
|
||||
QuickCustomizationVisibilitiesContainer::
|
||||
QuickCustomizationVisibilitiesContainer() {}
|
||||
|
||||
bool QuickCustomizationVisibilitiesContainer::IsEmpty() const {
|
||||
return visibilities.empty();
|
||||
}
|
||||
|
||||
void QuickCustomizationVisibilitiesContainer::Set(
|
||||
const gd::String& name, QuickCustomization::Visibility visibility) {
|
||||
visibilities[name] = visibility;
|
||||
}
|
||||
|
||||
QuickCustomization::Visibility QuickCustomizationVisibilitiesContainer::Get(
|
||||
const gd::String& name) const {
|
||||
auto it = visibilities.find(name);
|
||||
if (it != visibilities.end()) return it->second;
|
||||
|
||||
return QuickCustomization::Visibility::Default;
|
||||
}
|
||||
|
||||
void QuickCustomizationVisibilitiesContainer::SerializeTo(
|
||||
SerializerElement& element) const {
|
||||
for (auto& visibility : visibilities) {
|
||||
element.SetStringAttribute(
|
||||
visibility.first,
|
||||
QuickCustomization::VisibilityAsString(visibility.second));
|
||||
}
|
||||
}
|
||||
|
||||
void QuickCustomizationVisibilitiesContainer::UnserializeFrom(
|
||||
const SerializerElement& element) {
|
||||
visibilities.clear();
|
||||
for (auto& child : element.GetAllChildren()) {
|
||||
visibilities[child.first] =
|
||||
QuickCustomization::StringAsVisibility(child.second->GetStringValue());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace gd
|
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "GDCore/Project/QuickCustomization.h"
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
|
||||
namespace gd {
|
||||
|
||||
class QuickCustomizationVisibilitiesContainer {
|
||||
public:
|
||||
QuickCustomizationVisibilitiesContainer();
|
||||
|
||||
void Set(const gd::String& name, QuickCustomization::Visibility visibility);
|
||||
|
||||
QuickCustomization::Visibility Get(const gd::String& name) const;
|
||||
|
||||
bool IsEmpty() const;
|
||||
|
||||
void SerializeTo(SerializerElement& element) const;
|
||||
|
||||
void UnserializeFrom(const SerializerElement& element);
|
||||
|
||||
private:
|
||||
std::map<gd::String, QuickCustomization::Visibility> visibilities;
|
||||
};
|
||||
|
||||
} // namespace gd
|
@@ -152,8 +152,8 @@ class GD_CORE_API Resource {
|
||||
gd::String metadata;
|
||||
gd::String originName;
|
||||
gd::String originIdentifier;
|
||||
bool userAdded; ///< True if the resource was added by the user, and not
|
||||
///< automatically by GDevelop.
|
||||
bool userAdded = false; ///< True if the resource was added by the user, and not
|
||||
///< automatically by GDevelop.
|
||||
|
||||
static gd::String badStr;
|
||||
};
|
||||
|
@@ -87,20 +87,6 @@ class GD_CORE_API SourceFile {
|
||||
///< SetAssociatedEvent.
|
||||
};
|
||||
|
||||
//"Tool" Functions
|
||||
|
||||
/**
|
||||
* Functor testing Source Files name
|
||||
*/
|
||||
struct ExternalSourceFileHasName
|
||||
: public std::
|
||||
binary_function<std::unique_ptr<SourceFile>, gd::String, bool> {
|
||||
bool operator()(const std::unique_ptr<SourceFile>& externalEvents,
|
||||
gd::String name) const {
|
||||
return externalEvents->GetFileName() == name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace gd
|
||||
|
||||
#endif // SOURCEFILE_H
|
||||
|
@@ -33,7 +33,7 @@ class GD_CORE_API Variable {
|
||||
Unknown,
|
||||
/** Used when objects of a group have different types for a variable. */
|
||||
MixedTypes,
|
||||
|
||||
|
||||
// Primitive types
|
||||
String,
|
||||
Number,
|
||||
@@ -393,11 +393,11 @@ class GD_CORE_API Variable {
|
||||
*/
|
||||
static Type StringAsType(const gd::String& str);
|
||||
|
||||
bool folded;
|
||||
bool folded = false;
|
||||
mutable Type type;
|
||||
mutable gd::String str;
|
||||
mutable double value;
|
||||
mutable bool boolVal;
|
||||
mutable bool boolVal = false;
|
||||
mutable bool hasMixedValues;
|
||||
mutable std::map<gd::String, std::shared_ptr<Variable>>
|
||||
children; ///< Children, when the variable is considered as a structure.
|
||||
|
@@ -187,7 +187,7 @@ class GD_CORE_API VariablesContainer {
|
||||
///@}
|
||||
|
||||
private:
|
||||
SourceType sourceType;
|
||||
SourceType sourceType = Unknown;
|
||||
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.
|
||||
|
@@ -456,13 +456,13 @@ class GD_CORE_API SerializerElement {
|
||||
*/
|
||||
void Init(const gd::SerializerElement &other);
|
||||
|
||||
bool valueUndefined; ///< If true, the element does not have a value.
|
||||
bool valueUndefined = true; ///< If true, the element does not have a value.
|
||||
SerializerValue elementValue;
|
||||
|
||||
std::map<gd::String, SerializerValue> attributes;
|
||||
std::vector<std::pair<gd::String, std::shared_ptr<SerializerElement> > >
|
||||
children;
|
||||
mutable bool isArray; ///< true if element is considered as an array
|
||||
mutable bool isArray = false; ///< true if element is considered as an array
|
||||
mutable gd::String arrayOf; ///< The name of the children (was useful for XML
|
||||
///< parsed elements).
|
||||
mutable gd::String deprecatedArrayOf; ///< Alternate name for children
|
||||
|
2
Core/GDCore/Serialization/rapidjson/.clang-tidy
Normal file
2
Core/GDCore/Serialization/rapidjson/.clang-tidy
Normal file
@@ -0,0 +1,2 @@
|
||||
# Disable all checks in this folder.
|
||||
Checks: '-*'
|
@@ -4,6 +4,8 @@
|
||||
* This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
#include "GDCore/String.h"
|
||||
|
||||
#include <algorithm>
|
||||
@@ -825,3 +827,5 @@ bool GD_CORE_API CaseInsensitiveEquiv( const String &lhs, const String &rhs, boo
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// NOLINTEND
|
||||
|
@@ -4,6 +4,8 @@
|
||||
* This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
#ifndef GDCORE_UTF8_STRING_H
|
||||
#define GDCORE_UTF8_STRING_H
|
||||
|
||||
@@ -898,3 +900,5 @@ namespace std
|
||||
* In Unicode, uppercasing/lowercasing strings to compare them in a case-insensitive way is not recommended.
|
||||
* That's why the function gd::CaseInsensitiveEquiv exists to compare two strings in a case-insensitive way.
|
||||
*/
|
||||
|
||||
// NOLINTEND
|
@@ -2,6 +2,7 @@
|
||||
#define GD_CORE_POLYMORPHICCLONE_H
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace gd {
|
||||
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* Copyright 2008-present Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
#include <algorithm>
|
||||
#include "GDCore/Serialization/SerializerElement.h"
|
||||
#include "GDCore/String.h"
|
||||
#include "GDCore/Tools/MakeUnique.h"
|
||||
|
@@ -3,6 +3,9 @@
|
||||
* Copyright 2008-2016 Florian Rival (Florian.Rival@gmail.com). All rights
|
||||
* reserved. This project is released under the MIT License.
|
||||
*/
|
||||
|
||||
// NOLINTBEGIN
|
||||
|
||||
#include "SystemStats.h"
|
||||
#include "stdio.h"
|
||||
#include "stdlib.h"
|
||||
@@ -49,3 +52,5 @@ size_t SystemStats::GetUsedVirtualMemory() {
|
||||
}
|
||||
|
||||
} // namespace gd
|
||||
|
||||
// NOLINTEND
|
2
Core/GDCore/Tools/UUID/.clang-tidy
Normal file
2
Core/GDCore/Tools/UUID/.clang-tidy
Normal file
@@ -0,0 +1,2 @@
|
||||
# Disable all checks in this folder.
|
||||
Checks: '-*'
|
2
Core/GDCore/Utf8/.clang-tidy
Normal file
2
Core/GDCore/Utf8/.clang-tidy
Normal file
@@ -0,0 +1,2 @@
|
||||
# Disable all checks in this folder.
|
||||
Checks: '-*'
|
@@ -1992,7 +1992,7 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
// A behavior is copied from one extension to another.
|
||||
// An events-based behavior is copied from one extension to another.
|
||||
|
||||
auto &destinationExtension =
|
||||
project.InsertNewEventsFunctionsExtension("DestinationExtension", 0);
|
||||
@@ -2001,21 +2001,19 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
// instruction keeps pointing to the old extension.
|
||||
destinationExtension.InsertNewEventsFunction("MyEventsFunction", 0);
|
||||
|
||||
auto &copiedBehavior =
|
||||
auto &duplicatedBehavior =
|
||||
destinationExtension.GetEventsBasedBehaviors().InsertNew(
|
||||
"MyOtherEventsBasedBehavior", 0);
|
||||
copiedBehavior.SetFullName("My events based behavior");
|
||||
copiedBehavior.SetDescription("An events based behavior for test");
|
||||
copiedBehavior.SetObjectType("MyEventsExtension::MyEventsBasedObject");
|
||||
duplicatedBehavior.SetObjectType("MyEventsExtension::MyEventsBasedObject");
|
||||
|
||||
// Add the copied events.
|
||||
auto &behaviorEventsFunctions = copiedBehavior.GetEventsFunctions();
|
||||
auto &behaviorAction = behaviorEventsFunctions.InsertNewEventsFunction(
|
||||
"MyBehaviorEventsFunction", 0);
|
||||
auto &eventsFunctions = duplicatedBehavior.GetEventsFunctions();
|
||||
auto &behaviorAction = eventsFunctions.InsertNewEventsFunction(
|
||||
"MyObjectEventsFunction", 0);
|
||||
SetupEvents(behaviorAction.GetEvents());
|
||||
|
||||
gd::WholeProjectRefactorer::UpdateExtensionNameInEventsBasedBehavior(
|
||||
project, destinationExtension, copiedBehavior, "MyEventsExtension");
|
||||
project, destinationExtension, duplicatedBehavior, "MyEventsExtension");
|
||||
|
||||
// Check that events function calls in instructions have been renamed
|
||||
REQUIRE(GetEventFirstActionType(behaviorAction.GetEvents().GetEvent(
|
||||
@@ -2023,13 +2021,123 @@ TEST_CASE("WholeProjectRefactorer", "[common]") {
|
||||
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check that events function calls in instructions have NOT been renamed
|
||||
// outside of the copied behavior.
|
||||
// outside of the copied events-based behavior.
|
||||
REQUIRE(
|
||||
GetEventFirstActionType(eventsList->GetEvent(FreeFunctionAction)) ==
|
||||
"MyEventsExtension::MyEventsFunction");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Events extension renamed in instructions scoped to one object") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
// An events-based object is copied from one extension to another.
|
||||
|
||||
auto &destinationExtension =
|
||||
project.InsertNewEventsFunctionsExtension("DestinationExtension", 0);
|
||||
// Add the function used by the instruction that is checked in this test.
|
||||
// When the function doesn't exist the destination extension, the
|
||||
// instruction keeps pointing to the old extension.
|
||||
destinationExtension.InsertNewEventsFunction("MyEventsFunction", 0);
|
||||
|
||||
auto &duplicatedObject =
|
||||
destinationExtension.GetEventsBasedObjects().InsertNew(
|
||||
"MyDuplicatedEventsBasedObject", 0);
|
||||
|
||||
// Add the copied events.
|
||||
auto &eventsFunctions = duplicatedObject.GetEventsFunctions();
|
||||
auto &objectAction = eventsFunctions.InsertNewEventsFunction(
|
||||
"MyBehaviorEventsFunction", 0);
|
||||
SetupEvents(objectAction.GetEvents());
|
||||
|
||||
gd::WholeProjectRefactorer::UpdateExtensionNameInEventsBasedObject(
|
||||
project, destinationExtension, duplicatedObject, "MyEventsExtension");
|
||||
|
||||
// Check that events function calls in instructions have been renamed
|
||||
REQUIRE(GetEventFirstActionType(objectAction.GetEvents().GetEvent(
|
||||
FreeFunctionAction)) == "DestinationExtension::MyEventsFunction");
|
||||
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check that events function calls in instructions have NOT been renamed
|
||||
// outside of the copied events-based object.
|
||||
REQUIRE(
|
||||
GetEventFirstActionType(eventsList->GetEvent(FreeFunctionAction)) ==
|
||||
"MyEventsExtension::MyEventsFunction");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Events-based behavior renamed in instructions scoped to one behavior") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
// An events-based behavior is duplicated in the same extension.
|
||||
auto &duplicatedBehavior =
|
||||
eventsExtension.GetEventsBasedBehaviors().InsertNew(
|
||||
"MyDuplicatedEventsBasedBehavior", 0);
|
||||
duplicatedBehavior.SetObjectType("MyEventsExtension::MyEventsBasedObject");
|
||||
|
||||
// Add the copied events.
|
||||
auto &eventsFunctions = duplicatedBehavior.GetEventsFunctions();
|
||||
auto &behaviorAction = eventsFunctions.InsertNewEventsFunction(
|
||||
"MyBehaviorEventsFunction", 0);
|
||||
SetupEvents(behaviorAction.GetEvents());
|
||||
|
||||
gd::WholeProjectRefactorer::UpdateBehaviorNameInEventsBasedBehavior(
|
||||
project, eventsExtension, duplicatedBehavior, "MyEventsBasedBehavior");
|
||||
|
||||
// Check that events function calls in instructions have been renamed
|
||||
REQUIRE(GetEventFirstActionType(
|
||||
behaviorAction.GetEvents().GetEvent(BehaviorAction)) ==
|
||||
"MyEventsExtension::MyDuplicatedEventsBasedBehavior::MyBehaviorEventsFunction");
|
||||
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check that events function calls in instructions have NOT been renamed
|
||||
// outside of the duplicated events-based behavior.
|
||||
REQUIRE(
|
||||
GetEventFirstActionType(eventsList->GetEvent(BehaviorAction)) ==
|
||||
"MyEventsExtension::MyEventsBasedBehavior::MyBehaviorEventsFunction");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Events-based object renamed in instructions scoped to one object") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
SetupProjectWithDummyPlatform(project, platform);
|
||||
auto &eventsExtension = SetupProjectWithEventsFunctionExtension(project);
|
||||
|
||||
// An events-based object is duplicated in the same extension.
|
||||
auto &duplicatedObject =
|
||||
eventsExtension.GetEventsBasedObjects().InsertNew(
|
||||
"MyDuplicatedEventsBasedObject", 0);
|
||||
|
||||
// Add the copied events.
|
||||
auto &eventsFunctions = duplicatedObject.GetEventsFunctions();
|
||||
auto &objectAction = eventsFunctions.InsertNewEventsFunction(
|
||||
"MyObjectEventsFunction", 0);
|
||||
SetupEvents(objectAction.GetEvents());
|
||||
|
||||
gd::WholeProjectRefactorer::UpdateObjectNameInEventsBasedObject(
|
||||
project, eventsExtension, duplicatedObject, "MyEventsBasedObject");
|
||||
|
||||
// Check that events function calls in instructions have been renamed
|
||||
REQUIRE(GetEventFirstActionType(
|
||||
objectAction.GetEvents().GetEvent(ObjectAction)) ==
|
||||
"MyEventsExtension::MyDuplicatedEventsBasedObject::MyObjectEventsFunction");
|
||||
|
||||
for (auto *eventsList : GetEventsLists(project)) {
|
||||
// Check that events function calls in instructions have NOT been renamed
|
||||
// outside of the duplicated events-based object.
|
||||
REQUIRE(
|
||||
GetEventFirstActionType(eventsList->GetEvent(ObjectAction)) ==
|
||||
"MyEventsExtension::MyEventsBasedObject::MyObjectEventsFunction");
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Events extension renamed in parameters") {
|
||||
gd::Project project;
|
||||
gd::Platform platform;
|
||||
|
@@ -164,8 +164,18 @@ namespace gdjs {
|
||||
this.setWidth(initialInstanceData.width);
|
||||
this.setHeight(initialInstanceData.height);
|
||||
}
|
||||
if (initialInstanceData.depth !== undefined)
|
||||
if (initialInstanceData.depth !== undefined) {
|
||||
this.setDepth(initialInstanceData.depth);
|
||||
}
|
||||
if (initialInstanceData.flippedX) {
|
||||
this.flipX(initialInstanceData.flippedX);
|
||||
}
|
||||
if (initialInstanceData.flippedY) {
|
||||
this.flipY(initialInstanceData.flippedY);
|
||||
}
|
||||
if (initialInstanceData.flippedZ) {
|
||||
this.flipZ(initialInstanceData.flippedZ);
|
||||
}
|
||||
}
|
||||
|
||||
setX(x: float): void {
|
||||
|
@@ -73,9 +73,7 @@ namespace gdjs {
|
||||
}
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.light.color.setHex(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
);
|
||||
this.light.color.setHex(gdjs.rgbOrHexStringToNumber(value));
|
||||
}
|
||||
}
|
||||
updateColorParameter(parameterName: string, value: number): void {
|
||||
|
@@ -72,8 +72,18 @@ namespace gdjs {
|
||||
|
||||
extraInitializationFromInitialInstance(initialInstanceData: InstanceData) {
|
||||
super.extraInitializationFromInitialInstance(initialInstanceData);
|
||||
if (initialInstanceData.depth !== undefined)
|
||||
if (initialInstanceData.depth !== undefined) {
|
||||
this.setDepth(initialInstanceData.depth);
|
||||
}
|
||||
if (initialInstanceData.flippedX) {
|
||||
this.flipX(initialInstanceData.flippedX);
|
||||
}
|
||||
if (initialInstanceData.flippedY) {
|
||||
this.flipY(initialInstanceData.flippedY);
|
||||
}
|
||||
if (initialInstanceData.flippedZ) {
|
||||
this.flipZ(initialInstanceData.flippedZ);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -94,7 +94,7 @@ namespace gdjs {
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.light.color = new THREE.Color(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
gdjs.rgbOrHexStringToNumber(value)
|
||||
);
|
||||
}
|
||||
if (parameterName === 'top') {
|
||||
|
@@ -71,7 +71,7 @@ namespace gdjs {
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.fog.color = new THREE.Color(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
gdjs.rgbOrHexStringToNumber(value)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -95,12 +95,12 @@ namespace gdjs {
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'skyColor') {
|
||||
this.light.color = new THREE.Color(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
gdjs.rgbOrHexStringToNumber(value)
|
||||
);
|
||||
}
|
||||
if (parameterName === 'groundColor') {
|
||||
this.light.groundColor = new THREE.Color(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
gdjs.rgbOrHexStringToNumber(value)
|
||||
);
|
||||
}
|
||||
if (parameterName === 'top') {
|
||||
|
@@ -803,11 +803,8 @@ module.exports = {
|
||||
}
|
||||
|
||||
const Cube3DObject = new gd.ObjectJsImplementation();
|
||||
Cube3DObject.updateProperty = function (
|
||||
objectContent,
|
||||
propertyName,
|
||||
newValue
|
||||
) {
|
||||
Cube3DObject.updateProperty = function (propertyName, newValue) {
|
||||
const objectContent = this.content;
|
||||
if (
|
||||
propertyName === 'width' ||
|
||||
propertyName === 'height' ||
|
||||
@@ -851,8 +848,9 @@ module.exports = {
|
||||
|
||||
return false;
|
||||
};
|
||||
Cube3DObject.getProperties = function (objectContent) {
|
||||
Cube3DObject.getProperties = function () {
|
||||
const objectProperties = new gd.MapStringPropertyDescriptor();
|
||||
const objectContent = this.content;
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('enableTextureTransparency')
|
||||
@@ -878,7 +876,8 @@ module.exports = {
|
||||
'The top of each image can touch the **top face** (Y) or the **front face** (Z).'
|
||||
)
|
||||
)
|
||||
.setGroup(_('Face orientation'));
|
||||
.setGroup(_('Face orientation'))
|
||||
.setAdvanced(true);
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('width')
|
||||
@@ -909,7 +908,7 @@ module.exports = {
|
||||
.setValue(objectContent.frontFaceResourceName || '')
|
||||
.setType('resource')
|
||||
.addExtraInfo('image')
|
||||
.setLabel(_('Front face image'))
|
||||
.setLabel(_('Front face'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
@@ -917,7 +916,7 @@ module.exports = {
|
||||
.setValue(objectContent.backFaceResourceName || '')
|
||||
.setType('resource')
|
||||
.addExtraInfo('image')
|
||||
.setLabel(_('Back face image'))
|
||||
.setLabel(_('Back face'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
@@ -932,14 +931,15 @@ module.exports = {
|
||||
'The top of the image can touch the **top face** (Y) or the **bottom face** (X).'
|
||||
)
|
||||
)
|
||||
.setGroup(_('Textures'));
|
||||
.setGroup(_('Face orientation'))
|
||||
.setAdvanced(true);
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('leftFaceResourceName')
|
||||
.setValue(objectContent.leftFaceResourceName || '')
|
||||
.setType('resource')
|
||||
.addExtraInfo('image')
|
||||
.setLabel(_('Left face image'))
|
||||
.setLabel(_('Left face'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
@@ -947,7 +947,7 @@ module.exports = {
|
||||
.setValue(objectContent.rightFaceResourceName || '')
|
||||
.setType('resource')
|
||||
.addExtraInfo('image')
|
||||
.setLabel(_('Right face image'))
|
||||
.setLabel(_('Right face'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
@@ -955,7 +955,7 @@ module.exports = {
|
||||
.setValue(objectContent.topFaceResourceName || '')
|
||||
.setType('resource')
|
||||
.addExtraInfo('image')
|
||||
.setLabel(_('Top face image'))
|
||||
.setLabel(_('Top face'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
@@ -963,92 +963,98 @@ module.exports = {
|
||||
.setValue(objectContent.bottomFaceResourceName || '')
|
||||
.setType('resource')
|
||||
.addExtraInfo('image')
|
||||
.setLabel(_('Bottom face image'))
|
||||
.setLabel(_('Bottom face'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('frontFaceResourceRepeat')
|
||||
.setValue(objectContent.frontFaceResourceRepeat ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Tile front face image'))
|
||||
.setLabel(_('Tile'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('backFaceResourceRepeat')
|
||||
.setValue(objectContent.backFaceResourceRepeat ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Tile back face image'))
|
||||
.setLabel(_('Tile'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('leftFaceResourceRepeat')
|
||||
.setValue(objectContent.leftFaceResourceRepeat ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Tile left face image'))
|
||||
.setLabel(_('Tile'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('rightFaceResourceRepeat')
|
||||
.setValue(objectContent.rightFaceResourceRepeat ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Tile right face image'))
|
||||
.setLabel(_('Tile'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('topFaceResourceRepeat')
|
||||
.setValue(objectContent.topFaceResourceRepeat ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Tile top face image'))
|
||||
.setLabel(_('Tile'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('bottomFaceResourceRepeat')
|
||||
.setValue(objectContent.bottomFaceResourceRepeat ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Tile bottom face image'))
|
||||
.setLabel(_('Tile'))
|
||||
.setGroup(_('Textures'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('frontFaceVisible')
|
||||
.setValue(objectContent.frontFaceVisible ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Show front face'))
|
||||
.setGroup(_('Face visibility'));
|
||||
.setLabel(_('Front face'))
|
||||
.setGroup(_('Face visibility'))
|
||||
.setAdvanced(true);
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('backFaceVisible')
|
||||
.setValue(objectContent.backFaceVisible ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Show back face'))
|
||||
.setGroup(_('Face visibility'));
|
||||
.setLabel(_('Back face'))
|
||||
.setGroup(_('Face visibility'))
|
||||
.setAdvanced(true);
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('leftFaceVisible')
|
||||
.setValue(objectContent.leftFaceVisible ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Show left face'))
|
||||
.setGroup(_('Face visibility'));
|
||||
.setLabel(_('Left face'))
|
||||
.setGroup(_('Face visibility'))
|
||||
.setAdvanced(true);
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('rightFaceVisible')
|
||||
.setValue(objectContent.rightFaceVisible ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Show right face'))
|
||||
.setGroup(_('Face visibility'));
|
||||
.setLabel(_('Right face'))
|
||||
.setGroup(_('Face visibility'))
|
||||
.setAdvanced(true);
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('topFaceVisible')
|
||||
.setValue(objectContent.topFaceVisible ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Show top face'))
|
||||
.setGroup(_('Face visibility'));
|
||||
.setLabel(_('Top face'))
|
||||
.setGroup(_('Face visibility'))
|
||||
.setAdvanced(true);
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('bottomFaceVisible')
|
||||
.setValue(objectContent.bottomFaceVisible ? 'true' : 'false')
|
||||
.setType('boolean')
|
||||
.setLabel(_('Show bottom face'))
|
||||
.setGroup(_('Face visibility'));
|
||||
.setLabel(_('Bottom face'))
|
||||
.setGroup(_('Face visibility'))
|
||||
.setAdvanced(true);
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('materialType')
|
||||
@@ -1060,38 +1066,35 @@ module.exports = {
|
||||
|
||||
return objectProperties;
|
||||
};
|
||||
Cube3DObject.setRawJSONContent(
|
||||
JSON.stringify({
|
||||
width: 100,
|
||||
height: 100,
|
||||
depth: 100,
|
||||
enableTextureTransparency: false,
|
||||
facesOrientation: 'Y',
|
||||
frontFaceResourceName: '',
|
||||
backFaceResourceName: '',
|
||||
backFaceUpThroughWhichAxisRotation: 'X',
|
||||
leftFaceResourceName: '',
|
||||
rightFaceResourceName: '',
|
||||
topFaceResourceName: '',
|
||||
bottomFaceResourceName: '',
|
||||
frontFaceVisible: true,
|
||||
backFaceVisible: false,
|
||||
leftFaceVisible: true,
|
||||
rightFaceVisible: true,
|
||||
topFaceVisible: true,
|
||||
bottomFaceVisible: true,
|
||||
frontFaceResourceRepeat: false,
|
||||
backFaceResourceRepeat: false,
|
||||
leftFaceResourceRepeat: false,
|
||||
rightFaceResourceRepeat: false,
|
||||
topFaceResourceRepeat: false,
|
||||
bottomFaceResourceRepeat: false,
|
||||
materialType: 'Basic',
|
||||
})
|
||||
);
|
||||
Cube3DObject.content = {
|
||||
width: 100,
|
||||
height: 100,
|
||||
depth: 100,
|
||||
enableTextureTransparency: false,
|
||||
facesOrientation: 'Y',
|
||||
frontFaceResourceName: '',
|
||||
backFaceResourceName: '',
|
||||
backFaceUpThroughWhichAxisRotation: 'X',
|
||||
leftFaceResourceName: '',
|
||||
rightFaceResourceName: '',
|
||||
topFaceResourceName: '',
|
||||
bottomFaceResourceName: '',
|
||||
frontFaceVisible: true,
|
||||
backFaceVisible: false,
|
||||
leftFaceVisible: true,
|
||||
rightFaceVisible: true,
|
||||
topFaceVisible: true,
|
||||
bottomFaceVisible: true,
|
||||
frontFaceResourceRepeat: false,
|
||||
backFaceResourceRepeat: false,
|
||||
leftFaceResourceRepeat: false,
|
||||
rightFaceResourceRepeat: false,
|
||||
topFaceResourceRepeat: false,
|
||||
bottomFaceResourceRepeat: false,
|
||||
materialType: 'Basic',
|
||||
};
|
||||
|
||||
Cube3DObject.updateInitialInstanceProperty = function (
|
||||
objectContent,
|
||||
instance,
|
||||
propertyName,
|
||||
newValue
|
||||
@@ -1099,7 +1102,7 @@ module.exports = {
|
||||
return false;
|
||||
};
|
||||
|
||||
Cube3DObject.getInitialInstanceProperties = function (content, instance) {
|
||||
Cube3DObject.getInitialInstanceProperties = function (instance) {
|
||||
const instanceProperties = new gd.MapStringPropertyDescriptor();
|
||||
return instanceProperties;
|
||||
};
|
||||
@@ -2060,7 +2063,10 @@ module.exports = {
|
||||
};
|
||||
|
||||
const getFirstVisibleFaceResourceName = (objectConfiguration) => {
|
||||
const properties = objectConfiguration.getProperties();
|
||||
const object = gd.castObject(
|
||||
objectConfiguration,
|
||||
gd.ObjectJsImplementation
|
||||
);
|
||||
|
||||
const orderedFaces = [
|
||||
['frontFaceVisible', 'frontFaceResourceName'],
|
||||
@@ -2075,10 +2081,8 @@ module.exports = {
|
||||
faceVisibleProperty,
|
||||
faceResourceNameProperty,
|
||||
] of orderedFaces) {
|
||||
if (properties.get(faceVisibleProperty).getValue() === 'true') {
|
||||
const textureResource = properties
|
||||
.get(faceResourceNameProperty)
|
||||
.getValue();
|
||||
if (object.content[faceVisibleProperty]) {
|
||||
const textureResource = object.content[faceResourceNameProperty];
|
||||
if (textureResource) return textureResource;
|
||||
}
|
||||
}
|
||||
@@ -2124,10 +2128,14 @@ module.exports = {
|
||||
// Name of the resource that is rendered.
|
||||
// If no face is visible, this will be null.
|
||||
this._renderedResourceName = undefined;
|
||||
const properties = associatedObjectConfiguration.getProperties();
|
||||
this._defaultWidth = parseFloat(properties.get('width').getValue());
|
||||
this._defaultHeight = parseFloat(properties.get('height').getValue());
|
||||
this._defaultDepth = parseFloat(properties.get('depth').getValue());
|
||||
|
||||
const object = gd.castObject(
|
||||
this._associatedObjectConfiguration,
|
||||
gd.ObjectJsImplementation
|
||||
);
|
||||
this._defaultWidth = object.content.width;
|
||||
this._defaultHeight = object.content.height;
|
||||
this._defaultDepth = object.content.depth;
|
||||
|
||||
this._pixiObject = new PIXI.Container();
|
||||
this._pixiFallbackObject = new PIXI.Graphics();
|
||||
@@ -2216,8 +2224,14 @@ module.exports = {
|
||||
this._centerY / objectTextureFrame.height;
|
||||
|
||||
this._pixiTexturedObject.angle = this._instance.getAngle();
|
||||
this._pixiTexturedObject.scale.x = width / objectTextureFrame.width;
|
||||
this._pixiTexturedObject.scale.y = height / objectTextureFrame.height;
|
||||
const scaleX =
|
||||
(width / objectTextureFrame.width) *
|
||||
(this._instance.isFlippedX() ? -1 : 1);
|
||||
const scaleY =
|
||||
(height / objectTextureFrame.height) *
|
||||
(this._instance.isFlippedY() ? -1 : 1);
|
||||
this._pixiTexturedObject.scale.x = scaleX;
|
||||
this._pixiTexturedObject.scale.y = scaleY;
|
||||
|
||||
this._pixiTexturedObject.position.x =
|
||||
this._instance.getX() +
|
||||
@@ -2244,6 +2258,9 @@ module.exports = {
|
||||
this._pixiFallbackObject.position.y =
|
||||
this._instance.getY() + height / 2;
|
||||
this._pixiFallbackObject.angle = this._instance.getAngle();
|
||||
|
||||
if (this._instance.isFlippedX()) this._pixiFallbackObject.scale.x = -1;
|
||||
if (this._instance.isFlippedY()) this._pixiFallbackObject.scale.y = -1;
|
||||
}
|
||||
|
||||
update() {
|
||||
@@ -2306,70 +2323,67 @@ module.exports = {
|
||||
pixiResourcesLoader
|
||||
);
|
||||
|
||||
const properties = associatedObjectConfiguration.getProperties();
|
||||
this._defaultWidth = parseFloat(properties.get('width').getValue());
|
||||
this._defaultHeight = parseFloat(properties.get('height').getValue());
|
||||
this._defaultDepth = parseFloat(properties.get('depth').getValue());
|
||||
this._defaultWidth = 1;
|
||||
this._defaultHeight = 1;
|
||||
this._defaultDepth = 1;
|
||||
|
||||
this._pixiObject = new PIXI.Graphics();
|
||||
this._pixiContainer.addChild(this._pixiObject);
|
||||
|
||||
this._faceResourceNames = [
|
||||
properties.get('frontFaceResourceName').getValue(),
|
||||
properties.get('backFaceResourceName').getValue(),
|
||||
properties.get('leftFaceResourceName').getValue(),
|
||||
properties.get('rightFaceResourceName').getValue(),
|
||||
properties.get('topFaceResourceName').getValue(),
|
||||
properties.get('bottomFaceResourceName').getValue(),
|
||||
];
|
||||
this._faceVisibilities = [
|
||||
properties.get('frontFaceVisible').getValue() === 'true',
|
||||
properties.get('backFaceVisible').getValue() === 'true',
|
||||
properties.get('leftFaceVisible').getValue() === 'true',
|
||||
properties.get('rightFaceVisible').getValue() === 'true',
|
||||
properties.get('topFaceVisible').getValue() === 'true',
|
||||
properties.get('bottomFaceVisible').getValue() === 'true',
|
||||
];
|
||||
this._shouldRepeatTextureOnFace = [
|
||||
properties.get('frontFaceResourceRepeat').getValue() === 'true',
|
||||
properties.get('backFaceResourceRepeat').getValue() === 'true',
|
||||
properties.get('leftFaceResourceRepeat').getValue() === 'true',
|
||||
properties.get('rightFaceResourceRepeat').getValue() === 'true',
|
||||
properties.get('topFaceResourceRepeat').getValue() === 'true',
|
||||
properties.get('bottomFaceResourceRepeat').getValue() === 'true',
|
||||
];
|
||||
this._facesOrientation = properties.get('facesOrientation').getValue();
|
||||
this._backFaceUpThroughWhichAxisRotation = properties
|
||||
.get('backFaceUpThroughWhichAxisRotation')
|
||||
.getValue();
|
||||
this._shouldUseTransparentTexture =
|
||||
properties.get('enableTextureTransparency').getValue() === 'true';
|
||||
this._faceResourceNames = ['', '', '', '', '', ''];
|
||||
this._faceVisibilities = [true, true, true, true, true, true];
|
||||
this._shouldRepeatTextureOnFace = [true, true, true, true, true, true];
|
||||
this._facesOrientation = 'Y';
|
||||
this._backFaceUpThroughWhichAxisRotation = 'X';
|
||||
this._shouldUseTransparentTexture = false;
|
||||
|
||||
const geometry = new THREE.BoxGeometry(1, 1, 1);
|
||||
const materials = [
|
||||
this._getFaceMaterial(project, materialIndexToFaceIndex[0]),
|
||||
this._getFaceMaterial(project, materialIndexToFaceIndex[1]),
|
||||
this._getFaceMaterial(project, materialIndexToFaceIndex[2]),
|
||||
this._getFaceMaterial(project, materialIndexToFaceIndex[3]),
|
||||
this._getFaceMaterial(project, materialIndexToFaceIndex[4]),
|
||||
this._getFaceMaterial(project, materialIndexToFaceIndex[5]),
|
||||
getTransparentMaterial(),
|
||||
getTransparentMaterial(),
|
||||
getTransparentMaterial(),
|
||||
getTransparentMaterial(),
|
||||
getTransparentMaterial(),
|
||||
getTransparentMaterial(),
|
||||
];
|
||||
this._threeObject = new THREE.Mesh(geometry, materials);
|
||||
this._threeObject.rotation.order = 'ZYX';
|
||||
|
||||
this._threeGroup.add(this._threeObject);
|
||||
|
||||
this.updateThreeObject();
|
||||
}
|
||||
|
||||
_getFaceMaterial(project, faceIndex) {
|
||||
if (!this._faceVisibilities[faceIndex]) return getTransparentMaterial();
|
||||
async _updateThreeObjectMaterials() {
|
||||
const getFaceMaterial = async (project, faceIndex) => {
|
||||
if (!this._faceVisibilities[faceIndex])
|
||||
return getTransparentMaterial();
|
||||
|
||||
return this._pixiResourcesLoader.getThreeMaterial(
|
||||
project,
|
||||
this._faceResourceNames[faceIndex],
|
||||
{
|
||||
useTransparentTexture: this._shouldUseTransparentTexture,
|
||||
}
|
||||
);
|
||||
return await this._pixiResourcesLoader.getThreeMaterial(
|
||||
project,
|
||||
this._faceResourceNames[faceIndex],
|
||||
{
|
||||
useTransparentTexture: this._shouldUseTransparentTexture,
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const materials = await Promise.all([
|
||||
getFaceMaterial(this._project, materialIndexToFaceIndex[0]),
|
||||
getFaceMaterial(this._project, materialIndexToFaceIndex[1]),
|
||||
getFaceMaterial(this._project, materialIndexToFaceIndex[2]),
|
||||
getFaceMaterial(this._project, materialIndexToFaceIndex[3]),
|
||||
getFaceMaterial(this._project, materialIndexToFaceIndex[4]),
|
||||
getFaceMaterial(this._project, materialIndexToFaceIndex[5]),
|
||||
]);
|
||||
|
||||
this._threeObject.material[0] = materials[0];
|
||||
this._threeObject.material[1] = materials[1];
|
||||
this._threeObject.material[2] = materials[2];
|
||||
this._threeObject.material[3] = materials[3];
|
||||
this._threeObject.material[4] = materials[4];
|
||||
this._threeObject.material[5] = materials[5];
|
||||
|
||||
this._updateTextureUvMapping();
|
||||
}
|
||||
|
||||
static _getResourceNameToDisplay(objectConfiguration) {
|
||||
@@ -2377,6 +2391,15 @@ module.exports = {
|
||||
}
|
||||
|
||||
updateThreeObject() {
|
||||
const object = gd.castObject(
|
||||
this._associatedObjectConfiguration,
|
||||
gd.ObjectJsImplementation
|
||||
);
|
||||
|
||||
this._defaultWidth = object.content.width;
|
||||
this._defaultHeight = object.content.height;
|
||||
this._defaultDepth = object.content.depth;
|
||||
|
||||
const width = this.getWidth();
|
||||
const height = this.getHeight();
|
||||
const depth = this.getDepth();
|
||||
@@ -2393,14 +2416,107 @@ module.exports = {
|
||||
RenderedInstance.toRad(this._instance.getAngle())
|
||||
);
|
||||
|
||||
if (
|
||||
width !== this._threeObject.scale.width ||
|
||||
height !== this._threeObject.scale.height ||
|
||||
depth !== this._threeObject.scale.depth
|
||||
) {
|
||||
this._threeObject.scale.set(width, height, depth);
|
||||
this.updateTextureUvMapping();
|
||||
let materialsDirty = false;
|
||||
let uvMappingDirty = false;
|
||||
|
||||
const shouldUseTransparentTexture =
|
||||
object.content.enableTextureTransparency;
|
||||
if (this._shouldUseTransparentTexture !== shouldUseTransparentTexture) {
|
||||
this._shouldUseTransparentTexture = shouldUseTransparentTexture;
|
||||
materialsDirty = true;
|
||||
}
|
||||
|
||||
const faceResourceNames = [
|
||||
object.content.frontFaceResourceName,
|
||||
object.content.backFaceResourceName,
|
||||
object.content.leftFaceResourceName,
|
||||
object.content.rightFaceResourceName,
|
||||
object.content.topFaceResourceName,
|
||||
object.content.bottomFaceResourceName,
|
||||
];
|
||||
if (
|
||||
this._faceResourceNames[0] !== faceResourceNames[0] ||
|
||||
this._faceResourceNames[1] !== faceResourceNames[1] ||
|
||||
this._faceResourceNames[2] !== faceResourceNames[2] ||
|
||||
this._faceResourceNames[3] !== faceResourceNames[3] ||
|
||||
this._faceResourceNames[4] !== faceResourceNames[4] ||
|
||||
this._faceResourceNames[5] !== faceResourceNames[5]
|
||||
) {
|
||||
this._faceResourceNames = faceResourceNames;
|
||||
materialsDirty = true;
|
||||
}
|
||||
|
||||
const faceVisibilities = [
|
||||
object.content.frontFaceVisible,
|
||||
object.content.backFaceVisible,
|
||||
object.content.leftFaceVisible,
|
||||
object.content.rightFaceVisible,
|
||||
object.content.topFaceVisible,
|
||||
object.content.bottomFaceVisible,
|
||||
];
|
||||
if (
|
||||
this._faceVisibilities[0] !== faceVisibilities[0] ||
|
||||
this._faceVisibilities[1] !== faceVisibilities[1] ||
|
||||
this._faceVisibilities[2] !== faceVisibilities[2] ||
|
||||
this._faceVisibilities[3] !== faceVisibilities[3] ||
|
||||
this._faceVisibilities[4] !== faceVisibilities[4] ||
|
||||
this._faceVisibilities[5] !== faceVisibilities[5]
|
||||
) {
|
||||
this._faceVisibilities = faceVisibilities;
|
||||
materialsDirty = true;
|
||||
uvMappingDirty = true;
|
||||
}
|
||||
|
||||
const shouldRepeatTextureOnFace = [
|
||||
object.content.frontFaceResourceRepeat,
|
||||
object.content.backFaceResourceRepeat,
|
||||
object.content.leftFaceResourceRepeat,
|
||||
object.content.rightFaceResourceRepeat,
|
||||
object.content.topFaceResourceRepeat,
|
||||
object.content.bottomFaceResourceRepeat,
|
||||
];
|
||||
if (
|
||||
this._shouldRepeatTextureOnFace[0] !== shouldRepeatTextureOnFace[0] ||
|
||||
this._shouldRepeatTextureOnFace[1] !== shouldRepeatTextureOnFace[1] ||
|
||||
this._shouldRepeatTextureOnFace[2] !== shouldRepeatTextureOnFace[2] ||
|
||||
this._shouldRepeatTextureOnFace[3] !== shouldRepeatTextureOnFace[3] ||
|
||||
this._shouldRepeatTextureOnFace[4] !== shouldRepeatTextureOnFace[4] ||
|
||||
this._shouldRepeatTextureOnFace[5] !== shouldRepeatTextureOnFace[5]
|
||||
) {
|
||||
this._shouldRepeatTextureOnFace = shouldRepeatTextureOnFace;
|
||||
uvMappingDirty = true;
|
||||
}
|
||||
|
||||
const backFaceUpThroughWhichAxisRotation =
|
||||
object.content.backFaceUpThroughWhichAxisRotation;
|
||||
if (
|
||||
backFaceUpThroughWhichAxisRotation !==
|
||||
this._backFaceUpThroughWhichAxisRotation
|
||||
) {
|
||||
this._backFaceUpThroughWhichAxisRotation = backFaceUpThroughWhichAxisRotation;
|
||||
uvMappingDirty = true;
|
||||
}
|
||||
|
||||
const facesOrientation = object.content.facesOrientation;
|
||||
if (facesOrientation !== this._facesOrientation) {
|
||||
this._facesOrientation = facesOrientation;
|
||||
uvMappingDirty = true;
|
||||
}
|
||||
|
||||
const scaleX = width * (this._instance.isFlippedX() ? -1 : 1);
|
||||
const scaleY = height * (this._instance.isFlippedY() ? -1 : 1);
|
||||
const scaleZ = depth * (this._instance.isFlippedZ() ? -1 : 1);
|
||||
if (
|
||||
scaleX !== this._threeObject.scale.x ||
|
||||
scaleY !== this._threeObject.scale.y ||
|
||||
scaleZ !== this._threeObject.scale.z
|
||||
) {
|
||||
this._threeObject.scale.set(scaleX, scaleY, scaleZ);
|
||||
uvMappingDirty = true;
|
||||
}
|
||||
|
||||
if (materialsDirty) this._updateThreeObjectMaterials();
|
||||
if (uvMappingDirty) this._updateTextureUvMapping();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2409,7 +2525,7 @@ module.exports = {
|
||||
* The mesh must be configured with a list of materials in order
|
||||
* for the method to work.
|
||||
*/
|
||||
updateTextureUvMapping() {
|
||||
_updateTextureUvMapping() {
|
||||
// @ts-ignore - position is stored as a Float32BufferAttribute
|
||||
/** @type {THREE.BufferAttribute} */
|
||||
const pos = this._threeObject.geometry.getAttribute('position');
|
||||
@@ -2683,25 +2799,23 @@ module.exports = {
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
const properties = associatedObjectConfiguration.getProperties();
|
||||
this._defaultWidth = parseFloat(properties.get('width').getValue());
|
||||
this._defaultHeight = parseFloat(properties.get('height').getValue());
|
||||
this._defaultDepth = parseFloat(properties.get('depth').getValue());
|
||||
const rotationX = parseFloat(properties.get('rotationX').getValue());
|
||||
const rotationY = parseFloat(properties.get('rotationY').getValue());
|
||||
const rotationZ = parseFloat(properties.get('rotationZ').getValue());
|
||||
const keepAspectRatio =
|
||||
properties.get('keepAspectRatio').getValue() === 'true';
|
||||
const modelResourceName = properties
|
||||
.get('modelResourceName')
|
||||
.getValue();
|
||||
this._originPoint = getPointForLocation(
|
||||
properties.get('originLocation').getValue()
|
||||
);
|
||||
this._centerPoint = getPointForLocation(
|
||||
properties.get('centerLocation').getValue()
|
||||
const object = gd.castObject(
|
||||
this._associatedObjectConfiguration,
|
||||
gd.Model3DObjectConfiguration
|
||||
);
|
||||
|
||||
this._defaultWidth = object.getWidth();
|
||||
this._defaultHeight = object.getHeight();
|
||||
this._defaultDepth = object.getDepth();
|
||||
const rotationX = object.getRotationX();
|
||||
const rotationY = object.getRotationY();
|
||||
const rotationZ = object.getRotationZ();
|
||||
const keepAspectRatio = object.shouldKeepAspectRatio();
|
||||
const modelResourceName = object.getModelResourceName();
|
||||
|
||||
this._originPoint = getPointForLocation(object.getOriginLocation());
|
||||
this._centerPoint = getPointForLocation(object.getCenterLocation());
|
||||
|
||||
// This renderer shows a placeholder for the object:
|
||||
this._pixiObject = new PIXI.Graphics();
|
||||
this._pixiContainer.addChild(this._pixiObject);
|
||||
@@ -2910,6 +3024,17 @@ module.exports = {
|
||||
}
|
||||
}
|
||||
|
||||
const isSamePoint = (point1, point2) => {
|
||||
if (!point1 && !point2) return true;
|
||||
if (point1 && !point2) return false;
|
||||
if (!point1 && point2) return false;
|
||||
return (
|
||||
point1[0] === point2[0] &&
|
||||
point1[1] === point2[1] &&
|
||||
point1[2] === point2[2]
|
||||
);
|
||||
};
|
||||
|
||||
const getPointForLocation = (location) => {
|
||||
switch (location) {
|
||||
case 'ModelOrigin':
|
||||
@@ -2946,24 +3071,20 @@ module.exports = {
|
||||
threeGroup,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
const properties = associatedObjectConfiguration.getProperties();
|
||||
this._defaultWidth = parseFloat(properties.get('width').getValue());
|
||||
this._defaultHeight = parseFloat(properties.get('height').getValue());
|
||||
this._defaultDepth = parseFloat(properties.get('depth').getValue());
|
||||
const rotationX = parseFloat(properties.get('rotationX').getValue());
|
||||
const rotationY = parseFloat(properties.get('rotationY').getValue());
|
||||
const rotationZ = parseFloat(properties.get('rotationZ').getValue());
|
||||
const keepAspectRatio =
|
||||
properties.get('keepAspectRatio').getValue() === 'true';
|
||||
const modelResourceName = properties
|
||||
.get('modelResourceName')
|
||||
.getValue();
|
||||
this._originPoint = getPointForLocation(
|
||||
properties.get('originLocation').getValue()
|
||||
);
|
||||
this._centerPoint = getPointForLocation(
|
||||
properties.get('centerLocation').getValue()
|
||||
);
|
||||
|
||||
this._defaultWidth = 1;
|
||||
this._defaultHeight = 1;
|
||||
this._defaultDepth = 1;
|
||||
this._originalWidth = 1;
|
||||
this._originalHeight = 1;
|
||||
this._originalDepth = 1;
|
||||
this._rotationX = 0;
|
||||
this._rotationY = 0;
|
||||
this._rotationZ = 0;
|
||||
this._keepAspectRatio = false;
|
||||
|
||||
this._originPoint = null;
|
||||
this._centerPoint = null;
|
||||
|
||||
this._pixiObject = new PIXI.Graphics();
|
||||
this._pixiContainer.addChild(this._pixiObject);
|
||||
@@ -2972,28 +3093,8 @@ module.exports = {
|
||||
this._threeObject.rotation.order = 'ZYX';
|
||||
this._threeGroup.add(this._threeObject);
|
||||
|
||||
this._pixiResourcesLoader
|
||||
.get3DModel(project, modelResourceName)
|
||||
.then((model3d) => {
|
||||
const clonedModel3D = THREE_ADDONS.SkeletonUtils.clone(
|
||||
model3d.scene
|
||||
);
|
||||
// This group hold the rotation defined by properties.
|
||||
const threeObject = new THREE.Group();
|
||||
threeObject.rotation.order = 'ZYX';
|
||||
threeObject.add(clonedModel3D);
|
||||
this._updateDefaultTransformation(
|
||||
threeObject,
|
||||
rotationX,
|
||||
rotationY,
|
||||
rotationZ,
|
||||
this._defaultWidth,
|
||||
this._defaultHeight,
|
||||
this._defaultDepth,
|
||||
keepAspectRatio
|
||||
);
|
||||
this._threeObject.add(threeObject);
|
||||
});
|
||||
this._threeModelGroup = null;
|
||||
this._clonedModel3D = null;
|
||||
}
|
||||
|
||||
getOriginX() {
|
||||
@@ -3034,23 +3135,28 @@ module.exports = {
|
||||
return this._centerPoint || this._modelOriginPoint;
|
||||
}
|
||||
|
||||
_updateDefaultTransformation(
|
||||
threeObject,
|
||||
rotationX,
|
||||
rotationY,
|
||||
rotationZ,
|
||||
originalWidth,
|
||||
originalHeight,
|
||||
originalDepth,
|
||||
keepAspectRatio
|
||||
) {
|
||||
threeObject.rotation.set(
|
||||
(rotationX * Math.PI) / 180,
|
||||
(rotationY * Math.PI) / 180,
|
||||
(rotationZ * Math.PI) / 180
|
||||
_updateDefaultTransformation() {
|
||||
if (!this._clonedModel3D) return; // Model is not ready - nothing to do.
|
||||
|
||||
if (this._threeModelGroup) {
|
||||
// Remove any previous container as we will recreate it just below
|
||||
this._threeObject.clear();
|
||||
}
|
||||
// This group hold the rotation defined by properties.
|
||||
// Always restart from a new group to avoid miscomputing bounding boxes/sizes.
|
||||
this._threeModelGroup = new THREE.Group();
|
||||
this._threeModelGroup.rotation.order = 'ZYX';
|
||||
this._threeModelGroup.add(this._clonedModel3D);
|
||||
|
||||
this._threeModelGroup.rotation.set(
|
||||
(this._rotationX * Math.PI) / 180,
|
||||
(this._rotationY * Math.PI) / 180,
|
||||
(this._rotationZ * Math.PI) / 180
|
||||
);
|
||||
this._threeModelGroup.updateMatrixWorld(true);
|
||||
const boundingBox = new THREE.Box3().setFromObject(
|
||||
this._threeModelGroup
|
||||
);
|
||||
threeObject.updateMatrixWorld(true);
|
||||
const boundingBox = new THREE.Box3().setFromObject(threeObject);
|
||||
|
||||
const shouldKeepModelOrigin = !this._originPoint;
|
||||
if (shouldKeepModelOrigin) {
|
||||
@@ -3077,7 +3183,7 @@ module.exports = {
|
||||
// Center the model.
|
||||
const centerPoint = this._centerPoint;
|
||||
if (centerPoint) {
|
||||
threeObject.position.set(
|
||||
this._threeModelGroup.position.set(
|
||||
-(boundingBox.min.x + modelWidth * centerPoint[0]),
|
||||
// The model is flipped on Y axis.
|
||||
-(boundingBox.min.y + modelHeight * (1 - centerPoint[1])),
|
||||
@@ -3086,11 +3192,11 @@ module.exports = {
|
||||
}
|
||||
|
||||
// Rotate the model.
|
||||
threeObject.scale.set(1, 1, 1);
|
||||
threeObject.rotation.set(
|
||||
(rotationX * Math.PI) / 180,
|
||||
(rotationY * Math.PI) / 180,
|
||||
(rotationZ * Math.PI) / 180
|
||||
this._threeModelGroup.scale.set(1, 1, 1);
|
||||
this._threeModelGroup.rotation.set(
|
||||
(this._rotationX * Math.PI) / 180,
|
||||
(this._rotationY * Math.PI) / 180,
|
||||
(this._rotationZ * Math.PI) / 180
|
||||
);
|
||||
|
||||
// Stretch the model in a 1x1x1 cube.
|
||||
@@ -3102,23 +3208,23 @@ module.exports = {
|
||||
// Flip on Y because the Y axis is on the opposite side of direct basis.
|
||||
// It avoids models to be like a mirror refection.
|
||||
scaleMatrix.makeScale(scaleX, -scaleY, scaleZ);
|
||||
threeObject.updateMatrix();
|
||||
threeObject.applyMatrix4(scaleMatrix);
|
||||
this._threeModelGroup.updateMatrix();
|
||||
this._threeModelGroup.applyMatrix4(scaleMatrix);
|
||||
|
||||
if (keepAspectRatio) {
|
||||
if (this._keepAspectRatio) {
|
||||
// Reduce the object dimensions to keep aspect ratio.
|
||||
const widthRatio =
|
||||
modelWidth < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalWidth / modelWidth;
|
||||
: this._originalWidth / modelWidth;
|
||||
const heightRatio =
|
||||
modelHeight < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalHeight / modelHeight;
|
||||
: this._originalHeight / modelHeight;
|
||||
const depthRatio =
|
||||
modelDepth < epsilon
|
||||
? Number.POSITIVE_INFINITY
|
||||
: originalDepth / modelDepth;
|
||||
: this._originalDepth / modelDepth;
|
||||
const minScaleRatio = Math.min(widthRatio, heightRatio, depthRatio);
|
||||
if (!Number.isFinite(minScaleRatio)) {
|
||||
this._defaultWidth = modelWidth;
|
||||
@@ -3126,48 +3232,124 @@ module.exports = {
|
||||
this._defaultDepth = modelDepth;
|
||||
} else {
|
||||
if (widthRatio === minScaleRatio) {
|
||||
this._defaultWidth = originalWidth;
|
||||
this._defaultWidth = this._originalWidth;
|
||||
this._defaultHeight = Rendered3DInstance.applyRatio({
|
||||
oldReferenceValue: modelWidth,
|
||||
newReferenceValue: originalWidth,
|
||||
newReferenceValue: this._originalWidth,
|
||||
valueToApplyTo: modelHeight,
|
||||
});
|
||||
this._defaultDepth = Rendered3DInstance.applyRatio({
|
||||
oldReferenceValue: modelWidth,
|
||||
newReferenceValue: originalWidth,
|
||||
newReferenceValue: this._originalWidth,
|
||||
valueToApplyTo: modelDepth,
|
||||
});
|
||||
} else if (heightRatio === minScaleRatio) {
|
||||
this._defaultWidth = Rendered3DInstance.applyRatio({
|
||||
oldReferenceValue: modelHeight,
|
||||
newReferenceValue: originalHeight,
|
||||
newReferenceValue: this._originalHeight,
|
||||
valueToApplyTo: modelWidth,
|
||||
});
|
||||
|
||||
this._defaultHeight = originalHeight;
|
||||
this._defaultHeight = this._originalHeight;
|
||||
this._defaultDepth = Rendered3DInstance.applyRatio({
|
||||
oldReferenceValue: modelHeight,
|
||||
newReferenceValue: originalHeight,
|
||||
newReferenceValue: this._originalHeight,
|
||||
valueToApplyTo: modelDepth,
|
||||
});
|
||||
} else {
|
||||
this._defaultWidth = Rendered3DInstance.applyRatio({
|
||||
oldReferenceValue: modelDepth,
|
||||
newReferenceValue: originalDepth,
|
||||
newReferenceValue: this._originalDepth,
|
||||
valueToApplyTo: modelWidth,
|
||||
});
|
||||
this._defaultHeight = Rendered3DInstance.applyRatio({
|
||||
oldReferenceValue: modelDepth,
|
||||
newReferenceValue: originalDepth,
|
||||
newReferenceValue: this._originalDepth,
|
||||
valueToApplyTo: modelHeight,
|
||||
});
|
||||
this._defaultDepth = originalDepth;
|
||||
this._defaultDepth = this._originalDepth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._threeObject.add(this._threeModelGroup);
|
||||
}
|
||||
|
||||
updateThreeObject() {
|
||||
const object = gd.castObject(
|
||||
this._associatedObjectConfiguration,
|
||||
gd.Model3DObjectConfiguration
|
||||
);
|
||||
|
||||
let defaultTransformationDirty = false;
|
||||
|
||||
const originalWidth = object.getWidth();
|
||||
const originalHeight = object.getHeight();
|
||||
const originalDepth = object.getDepth();
|
||||
if (
|
||||
this._originalWidth !== originalWidth ||
|
||||
this._originalHeight !== originalHeight ||
|
||||
this._originalDepth !== originalDepth
|
||||
) {
|
||||
this._originalWidth = originalWidth;
|
||||
this._originalHeight = originalHeight;
|
||||
this._originalDepth = originalDepth;
|
||||
defaultTransformationDirty = true;
|
||||
}
|
||||
|
||||
const rotationX = object.getRotationX();
|
||||
const rotationY = object.getRotationY();
|
||||
const rotationZ = object.getRotationZ();
|
||||
if (
|
||||
this._rotationX !== rotationX ||
|
||||
this._rotationY !== rotationY ||
|
||||
this._rotationZ !== rotationZ
|
||||
) {
|
||||
this._rotationX = rotationX;
|
||||
this._rotationY = rotationY;
|
||||
this._rotationZ = rotationZ;
|
||||
defaultTransformationDirty = true;
|
||||
}
|
||||
|
||||
const keepAspectRatio = object.shouldKeepAspectRatio();
|
||||
if (this._keepAspectRatio !== keepAspectRatio) {
|
||||
this._keepAspectRatio = keepAspectRatio;
|
||||
defaultTransformationDirty = true;
|
||||
}
|
||||
|
||||
const originPoint = getPointForLocation(object.getOriginLocation());
|
||||
if (!isSamePoint(originPoint, this._originPoint)) {
|
||||
this._originPoint = originPoint;
|
||||
defaultTransformationDirty = true;
|
||||
}
|
||||
|
||||
const centerPoint = getPointForLocation(object.getCenterLocation());
|
||||
if (!isSamePoint(centerPoint, this._centerPoint)) {
|
||||
this._centerPoint = centerPoint;
|
||||
defaultTransformationDirty = true;
|
||||
}
|
||||
|
||||
if (defaultTransformationDirty) this._updateDefaultTransformation();
|
||||
|
||||
const modelResourceName = object.getModelResourceName();
|
||||
if (this._modelResourceName !== modelResourceName) {
|
||||
this._modelResourceName = modelResourceName;
|
||||
|
||||
this._pixiResourcesLoader
|
||||
.get3DModel(this._project, modelResourceName)
|
||||
.then((model3d) => {
|
||||
this._clonedModel3D = THREE_ADDONS.SkeletonUtils.clone(
|
||||
model3d.scene
|
||||
);
|
||||
|
||||
this._updateDefaultTransformation();
|
||||
});
|
||||
}
|
||||
|
||||
this._updateThreeObjectPosition();
|
||||
}
|
||||
|
||||
_updateThreeObjectPosition() {
|
||||
const width = this.getWidth();
|
||||
const height = this.getHeight();
|
||||
const depth = this.getDepth();
|
||||
@@ -3186,12 +3368,16 @@ module.exports = {
|
||||
RenderedInstance.toRad(this._instance.getAngle())
|
||||
);
|
||||
|
||||
const scaleX = width * (this._instance.isFlippedX() ? -1 : 1);
|
||||
const scaleY = height * (this._instance.isFlippedY() ? -1 : 1);
|
||||
const scaleZ = depth * (this._instance.isFlippedZ() ? -1 : 1);
|
||||
|
||||
if (
|
||||
width !== this._threeObject.scale.width ||
|
||||
height !== this._threeObject.scale.height ||
|
||||
depth !== this._threeObject.scale.depth
|
||||
scaleX !== this._threeObject.scale.x ||
|
||||
scaleY !== this._threeObject.scale.y ||
|
||||
scaleZ !== this._threeObject.scale.z
|
||||
) {
|
||||
this._threeObject.scale.set(width, height, depth);
|
||||
this._threeObject.scale.set(scaleX, scaleY, scaleZ);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -76,7 +76,7 @@ namespace gdjs {
|
||||
updateStringParameter(parameterName: string, value: string): void {
|
||||
if (parameterName === 'color') {
|
||||
this.fog.color = new THREE.Color(
|
||||
gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value)
|
||||
gdjs.rgbOrHexStringToNumber(value)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -109,23 +109,26 @@ Model3DObjectConfiguration::GetProperties() const {
|
||||
objectProperties["rotationX"]
|
||||
.SetValue(gd::String::From(rotationX))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Rotation around X axis"))
|
||||
.SetLabel(_("X"))
|
||||
.SetDescription(_("Rotation around X axis"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
|
||||
.SetGroup(_("Default orientation"));
|
||||
.SetGroup(_("Default rotation"));
|
||||
|
||||
objectProperties["rotationY"]
|
||||
.SetValue(gd::String::From(rotationY))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Rotation around Y axis"))
|
||||
.SetLabel(_("Y"))
|
||||
.SetDescription(_("Rotation around Y axis"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
|
||||
.SetGroup(_("Default orientation"));
|
||||
.SetGroup(_("Default rotation"));
|
||||
|
||||
objectProperties["rotationZ"]
|
||||
.SetValue(gd::String::From(rotationZ))
|
||||
.SetType("number")
|
||||
.SetLabel(_("Rotation around Z axis"))
|
||||
.SetLabel(_("Z"))
|
||||
.SetDescription(_("Rotation around Z axis"))
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetDegreeAngle())
|
||||
.SetGroup(_("Default orientation"));
|
||||
.SetGroup(_("Default rotation"));
|
||||
|
||||
objectProperties["modelResourceName"]
|
||||
.SetValue(modelResourceName)
|
||||
@@ -139,7 +142,7 @@ Model3DObjectConfiguration::GetProperties() const {
|
||||
.AddExtraInfo("Basic")
|
||||
.AddExtraInfo("StandardWithoutMetalness")
|
||||
.AddExtraInfo("KeepOriginal")
|
||||
.SetLabel(_("Material modifier"));
|
||||
.SetLabel(_("Material"));
|
||||
|
||||
objectProperties["originLocation"]
|
||||
.SetValue(originLocation.empty() ? "TopLeft" : originLocation)
|
||||
@@ -149,7 +152,9 @@ Model3DObjectConfiguration::GetProperties() const {
|
||||
.AddExtraInfo("ObjectCenter")
|
||||
.AddExtraInfo("BottomCenterZ")
|
||||
.AddExtraInfo("BottomCenterY")
|
||||
.SetLabel(_("Origin point"));
|
||||
.SetLabel(_("Origin point"))
|
||||
.SetGroup(_("Points"))
|
||||
.SetAdvanced(true);
|
||||
|
||||
objectProperties["centerLocation"]
|
||||
.SetValue(centerLocation.empty() ? "ObjectCenter" : centerLocation)
|
||||
@@ -158,7 +163,9 @@ Model3DObjectConfiguration::GetProperties() const {
|
||||
.AddExtraInfo("ObjectCenter")
|
||||
.AddExtraInfo("BottomCenterZ")
|
||||
.AddExtraInfo("BottomCenterY")
|
||||
.SetLabel(_("Center point"));
|
||||
.SetLabel(_("Center point"))
|
||||
.SetGroup(_("Points"))
|
||||
.SetAdvanced(true);
|
||||
|
||||
return objectProperties;
|
||||
}
|
||||
|
@@ -140,7 +140,25 @@ public:
|
||||
const std::vector<Model3DAnimation> &GetAllAnimations() const {
|
||||
return animations;
|
||||
}
|
||||
///@}
|
||||
|
||||
/** \name Getters
|
||||
* Fast access for rendering instances.
|
||||
*/
|
||||
///@{
|
||||
double GetWidth() const { return width; };
|
||||
double GetHeight() const { return height; };
|
||||
double GetDepth() const { return depth; };
|
||||
double GetRotationX() const { return rotationX; };
|
||||
double GetRotationY() const { return rotationY; };
|
||||
double GetRotationZ() const { return rotationZ; };
|
||||
|
||||
const gd::String& GetModelResourceName() const { return modelResourceName; };
|
||||
const gd::String& GetMaterialType() const { return materialType; };
|
||||
const gd::String& GetOriginLocation() const { return originLocation; };
|
||||
const gd::String& GetCenterLocation() const { return centerLocation; };
|
||||
|
||||
bool shouldKeepAspectRatio() const { return keepAspectRatio; };
|
||||
///@}
|
||||
|
||||
protected:
|
||||
|
@@ -376,6 +376,9 @@ namespace gdjs {
|
||||
|
||||
setAnimationElapsedTime(time: float): void {
|
||||
this._renderer.setAnimationElapsedTime(time);
|
||||
if (!this._animationPaused) {
|
||||
this._renderer.resumeAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
getAnimationDuration(): float {
|
||||
|
@@ -7,15 +7,18 @@ namespace gdjs {
|
||||
export namespace evtTools {
|
||||
export namespace advancedWindow {
|
||||
const getElectronBrowserWindow = (runtimeScene: gdjs.RuntimeScene) => {
|
||||
const electronRemote = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getElectronRemote();
|
||||
if (electronRemote) {
|
||||
return electronRemote.getCurrentWindow();
|
||||
try {
|
||||
const electronRemote = runtimeScene
|
||||
.getGame()
|
||||
.getRenderer()
|
||||
.getElectronRemote();
|
||||
if (electronRemote) {
|
||||
return electronRemote.getCurrentWindow();
|
||||
}
|
||||
return null;
|
||||
} catch (error) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export const focus = function (
|
||||
|
@@ -66,7 +66,7 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
|
||||
.SetDescription(_("otherwise, objects are anchored according to the "
|
||||
"window size when the object is created."));
|
||||
|
||||
properties[_("Left edge anchor")]
|
||||
properties["leftEdgeAnchor"]
|
||||
.SetValue(GetAnchorAsString(static_cast<HorizontalAnchor>(
|
||||
behaviorContent.GetIntAttribute("leftEdgeAnchor"))))
|
||||
.SetType("Choice")
|
||||
@@ -75,9 +75,10 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
|
||||
.AddExtraInfo(_("Window center"))
|
||||
.AddExtraInfo(_("Window right"))
|
||||
.AddExtraInfo(_("Proportional"))
|
||||
.SetLabel(_("Left edge"))
|
||||
.SetDescription(_("Anchor the left edge of the object on X axis."));
|
||||
|
||||
properties[_("Right edge anchor")]
|
||||
properties["rightEdgeAnchor"]
|
||||
.SetValue(GetAnchorAsString(static_cast<HorizontalAnchor>(
|
||||
behaviorContent.GetIntAttribute("rightEdgeAnchor"))))
|
||||
.SetType("Choice")
|
||||
@@ -86,9 +87,10 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
|
||||
.AddExtraInfo(_("Window center"))
|
||||
.AddExtraInfo(_("Window right"))
|
||||
.AddExtraInfo(_("Proportional"))
|
||||
.SetLabel(_("Right edge"))
|
||||
.SetDescription(_("Anchor the right edge of the object on X axis."));
|
||||
|
||||
properties[_("Top edge anchor")]
|
||||
properties["topEdgeAnchor"]
|
||||
.SetValue(GetAnchorAsString(static_cast<VerticalAnchor>(
|
||||
behaviorContent.GetIntAttribute("topEdgeAnchor"))))
|
||||
.SetType("Choice")
|
||||
@@ -97,9 +99,10 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
|
||||
.AddExtraInfo(_("Window center"))
|
||||
.AddExtraInfo(_("Window bottom"))
|
||||
.AddExtraInfo(_("Proportional"))
|
||||
.SetLabel(_("Top edge"))
|
||||
.SetDescription(_("Anchor the top edge of the object on Y axis."));
|
||||
|
||||
properties[_("Bottom edge anchor")]
|
||||
properties["bottomEdgeAnchor"]
|
||||
.SetValue(GetAnchorAsString(static_cast<VerticalAnchor>(
|
||||
behaviorContent.GetIntAttribute("bottomEdgeAnchor"))))
|
||||
.SetType("Choice")
|
||||
@@ -108,19 +111,20 @@ std::map<gd::String, gd::PropertyDescriptor> AnchorBehavior::GetProperties(
|
||||
.AddExtraInfo(_("Window center"))
|
||||
.AddExtraInfo(_("Window bottom"))
|
||||
.AddExtraInfo(_("Proportional"))
|
||||
.SetLabel(_("Bottom edge"))
|
||||
.SetDescription(_("Anchor the bottom edge of the object on Y axis."));
|
||||
|
||||
properties[("useLegacyBottomAndRightAnchors")]
|
||||
properties["useLegacyBottomAndRightAnchors"]
|
||||
.SetLabel(_(
|
||||
"Stretch object when anchoring right or bottom edge (deprecated, "
|
||||
"it's recommended to leave this unchecked and anchor both sides if "
|
||||
"you want Sprite to stretch instead.)"))
|
||||
.SetGroup(_("Deprecated options (advanced)"))
|
||||
.SetValue(behaviorContent.GetBoolAttribute(
|
||||
"useLegacyBottomAndRightAnchors", true)
|
||||
? "true"
|
||||
: "false")
|
||||
.SetType("Boolean");
|
||||
.SetType("Boolean")
|
||||
.SetDeprecated(true);
|
||||
|
||||
return properties;
|
||||
}
|
||||
@@ -158,20 +162,20 @@ AnchorBehavior::VerticalAnchor GetVerticalAnchorFromString(
|
||||
bool AnchorBehavior::UpdateProperty(gd::SerializerElement& behaviorContent,
|
||||
const gd::String& name,
|
||||
const gd::String& value) {
|
||||
if (name == _("relativeToOriginalWindowSize"))
|
||||
if (name == "relativeToOriginalWindowSize")
|
||||
behaviorContent.SetAttribute("relativeToOriginalWindowSize", value == "1");
|
||||
else if (name == _("Left edge anchor"))
|
||||
else if (name == "leftEdgeAnchor")
|
||||
behaviorContent.SetAttribute(
|
||||
"leftEdgeAnchor",
|
||||
static_cast<int>(GetHorizontalAnchorFromString(value)));
|
||||
else if (name == _("Right edge anchor"))
|
||||
else if (name == "rightEdgeAnchor")
|
||||
behaviorContent.SetAttribute(
|
||||
"rightEdgeAnchor",
|
||||
static_cast<int>(GetHorizontalAnchorFromString(value)));
|
||||
else if (name == _("Top edge anchor"))
|
||||
else if (name == "topEdgeAnchor")
|
||||
behaviorContent.SetAttribute(
|
||||
"topEdgeAnchor", static_cast<int>(GetVerticalAnchorFromString(value)));
|
||||
else if (name == _("Bottom edge anchor"))
|
||||
else if (name == "bottomEdgeAnchor")
|
||||
behaviorContent.SetAttribute(
|
||||
"bottomEdgeAnchor",
|
||||
static_cast<int>(GetVerticalAnchorFromString(value)));
|
||||
|
@@ -88,7 +88,6 @@ namespace gdjs {
|
||||
const workingPoint: FloatPoint = gdjs.staticArray(
|
||||
gdjs.AnchorRuntimeBehavior.prototype.doStepPreEvents
|
||||
) as FloatPoint;
|
||||
// TODO EBO Make it work with event based objects or hide this behavior for them.
|
||||
let parentMinX = instanceContainer.getUnrotatedViewportMinX();
|
||||
let parentMinY = instanceContainer.getUnrotatedViewportMinY();
|
||||
let parentMaxX = instanceContainer.getUnrotatedViewportMaxX();
|
||||
@@ -111,10 +110,11 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
//Calculate the distances from the window's bounds.
|
||||
const topLeftPixel = layer.convertCoords(
|
||||
const topLeftPixel = this._convertCoords(
|
||||
instanceContainer,
|
||||
layer,
|
||||
this.owner.getDrawableX(),
|
||||
this.owner.getDrawableY(),
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
|
||||
@@ -141,10 +141,11 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
|
||||
const bottomRightPixel = layer.convertCoords(
|
||||
const bottomRightPixel = this._convertCoords(
|
||||
instanceContainer,
|
||||
layer,
|
||||
this.owner.getDrawableX() + this.owner.getWidth(),
|
||||
this.owner.getDrawableY() + this.owner.getHeight(),
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
|
||||
@@ -225,19 +226,21 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
// It's fine to reuse workingPoint as topLeftPixel is no longer used.
|
||||
const topLeftCoord = layer.convertInverseCoords(
|
||||
const topLeftCoord = this._convertInverseCoords(
|
||||
instanceContainer,
|
||||
layer,
|
||||
leftPixel,
|
||||
topPixel,
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
const left = topLeftCoord[0];
|
||||
const top = topLeftCoord[1];
|
||||
|
||||
const bottomRightCoord = layer.convertInverseCoords(
|
||||
const bottomRightCoord = this._convertInverseCoords(
|
||||
instanceContainer,
|
||||
layer,
|
||||
rightPixel,
|
||||
bottomPixel,
|
||||
0,
|
||||
workingPoint
|
||||
);
|
||||
const right = bottomRightCoord[0];
|
||||
@@ -270,8 +273,20 @@ namespace gdjs {
|
||||
this._rightEdgeAnchor !== HorizontalAnchor.None &&
|
||||
this._leftEdgeAnchor !== HorizontalAnchor.None
|
||||
) {
|
||||
this.owner.setWidth(right - left);
|
||||
this.owner.setX(left);
|
||||
const width = right - left;
|
||||
this.owner.setX(
|
||||
this.owner.getX() === this.owner.getDrawableX()
|
||||
? left
|
||||
: // It uses the position of the origin relatively to the object
|
||||
// size to apply it with the new size.
|
||||
// This is the same as doing:
|
||||
// lerp(left, right, (this.owner.getX() - this.owner.getDrawableX() / this.owner.getWidth())
|
||||
// But, the division is done at the end to avoid rounding errors.
|
||||
left +
|
||||
((this.owner.getX() - this.owner.getDrawableX()) * width) /
|
||||
this.owner.getWidth()
|
||||
);
|
||||
this.owner.setWidth(width);
|
||||
} else {
|
||||
if (this._leftEdgeAnchor !== HorizontalAnchor.None) {
|
||||
this.owner.setX(
|
||||
@@ -292,8 +307,15 @@ namespace gdjs {
|
||||
this._bottomEdgeAnchor !== VerticalAnchor.None &&
|
||||
this._topEdgeAnchor !== VerticalAnchor.None
|
||||
) {
|
||||
this.owner.setHeight(bottom - top);
|
||||
this.owner.setY(top);
|
||||
const height = bottom - top;
|
||||
this.owner.setY(
|
||||
this.owner.getY() === this.owner.getDrawableY()
|
||||
? top
|
||||
: top +
|
||||
((this.owner.getY() - this.owner.getDrawableY()) * height) /
|
||||
this.owner.getHeight()
|
||||
);
|
||||
this.owner.setHeight(height);
|
||||
} else {
|
||||
if (this._topEdgeAnchor !== VerticalAnchor.None) {
|
||||
this.owner.setY(
|
||||
@@ -314,6 +336,40 @@ namespace gdjs {
|
||||
}
|
||||
|
||||
doStepPostEvents(instanceContainer: gdjs.RuntimeInstanceContainer) {}
|
||||
|
||||
private _convertCoords(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: gdjs.RuntimeLayer,
|
||||
x: float,
|
||||
y: float,
|
||||
result: FloatPoint
|
||||
) {
|
||||
const isParentACustomObject =
|
||||
instanceContainer !== instanceContainer.getScene();
|
||||
if (isParentACustomObject) {
|
||||
result[0] = x;
|
||||
result[1] = y;
|
||||
return result;
|
||||
}
|
||||
return layer.convertCoords(x, y, 0, result);
|
||||
}
|
||||
|
||||
private _convertInverseCoords(
|
||||
instanceContainer: gdjs.RuntimeInstanceContainer,
|
||||
layer: gdjs.RuntimeLayer,
|
||||
x: float,
|
||||
y: float,
|
||||
result: FloatPoint
|
||||
) {
|
||||
const isParentACustomObject =
|
||||
instanceContainer !== instanceContainer.getScene();
|
||||
if (isParentACustomObject) {
|
||||
result[0] = x;
|
||||
result[1] = y;
|
||||
return result;
|
||||
}
|
||||
return layer.convertInverseCoords(x, y, 0, result);
|
||||
}
|
||||
}
|
||||
gdjs.registerBehavior(
|
||||
'AnchorBehavior::AnchorBehavior',
|
||||
|
@@ -70,6 +70,50 @@ describe('gdjs.AnchorRuntimeBehavior', function () {
|
||||
return object;
|
||||
}
|
||||
|
||||
const createSpriteWithOriginAtCenter = (behaviorProperties) => {
|
||||
const object = new gdjs.TestSpriteRuntimeObject(runtimeScene, {
|
||||
name: 'obj1',
|
||||
type: '',
|
||||
behaviors: [
|
||||
{
|
||||
name: anchorBehaviorName,
|
||||
type: 'AnchorBehavior::AnchorBehavior',
|
||||
// @ts-ignore - properties are not typed
|
||||
rightEdgeAnchor: 0,
|
||||
leftEdgeAnchor: 0,
|
||||
topEdgeAnchor: 0,
|
||||
bottomEdgeAnchor: 0,
|
||||
relativeToOriginalWindowSize: false,
|
||||
useLegacyBottomAndRightAnchors: false,
|
||||
...behaviorProperties,
|
||||
},
|
||||
],
|
||||
effects: [],
|
||||
animations: [
|
||||
{
|
||||
name: 'animation',
|
||||
directions: [
|
||||
{
|
||||
sprites: [
|
||||
{
|
||||
originPoint: { x: 50, y: 50 },
|
||||
centerPoint: { x: 50, y: 50 },
|
||||
points: [],
|
||||
hasCustomCollisionMask: false,
|
||||
customCollisionMask: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
object.setUnscaledWidthAndHeight(100, 100);
|
||||
object.setCustomWidthAndHeight(10, 10);
|
||||
runtimeScene.addObject(object);
|
||||
return object;
|
||||
};
|
||||
|
||||
describe('(anchor horizontal edge)', function () {
|
||||
['rightEdgeAnchor', 'leftEdgeAnchor'].forEach((objectEdge) => {
|
||||
it(`anchors the ${objectEdge} edge of object to window left (fixed)`, function () {
|
||||
@@ -200,5 +244,47 @@ describe('gdjs.AnchorRuntimeBehavior', function () {
|
||||
expect(object.getY()).to.equal(1000);
|
||||
expect(object.getWidth()).to.equal(10);
|
||||
});
|
||||
|
||||
it('can fill the screen with an object (with custom origin)', function () {
|
||||
setGameResolutionSizeAndStep(1000, 500);
|
||||
|
||||
const object = createSpriteWithOriginAtCenter({
|
||||
leftEdgeAnchor: 1,
|
||||
topEdgeAnchor: 1,
|
||||
rightEdgeAnchor: 2,
|
||||
bottomEdgeAnchor: 2,
|
||||
});
|
||||
object.setCustomWidthAndHeight(1000, 500);
|
||||
object.setPosition(500, 250);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
setGameResolutionSizeAndStep(2000, 3000);
|
||||
|
||||
expect(object.getX()).to.equal(1000);
|
||||
expect(object.getY()).to.equal(1500);
|
||||
expect(object.getWidth()).to.equal(2000);
|
||||
expect(object.getHeight()).to.equal(3000);
|
||||
});
|
||||
|
||||
it('can fill the screen with an object using proportional anchors (with custom origin)', () => {
|
||||
setGameResolutionSizeAndStep(1000, 500);
|
||||
|
||||
const object = createSpriteWithOriginAtCenter({
|
||||
leftEdgeAnchor: 3,
|
||||
topEdgeAnchor: 3,
|
||||
rightEdgeAnchor: 3,
|
||||
bottomEdgeAnchor: 3,
|
||||
});
|
||||
object.setCustomWidthAndHeight(1000, 500);
|
||||
object.setPosition(500, 250);
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
|
||||
setGameResolutionSizeAndStep(2000, 3000);
|
||||
|
||||
expect(object.getX()).to.equal(1000);
|
||||
expect(object.getY()).to.equal(1500);
|
||||
expect(object.getWidth()).to.equal(2000);
|
||||
expect(object.getHeight()).to.equal(3000);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -34,11 +34,8 @@ module.exports = {
|
||||
.setIcon('JsPlatform/Extensions/bbcode32.png');
|
||||
|
||||
var objectBBText = new gd.ObjectJsImplementation();
|
||||
objectBBText.updateProperty = function (
|
||||
objectContent,
|
||||
propertyName,
|
||||
newValue
|
||||
) {
|
||||
objectBBText.updateProperty = function (propertyName, newValue) {
|
||||
const objectContent = this.content;
|
||||
if (propertyName in objectContent) {
|
||||
if (typeof objectContent[propertyName] === 'boolean')
|
||||
objectContent[propertyName] = newValue === '1';
|
||||
@@ -50,8 +47,9 @@ module.exports = {
|
||||
|
||||
return false;
|
||||
};
|
||||
objectBBText.getProperties = function (objectContent) {
|
||||
objectBBText.getProperties = function () {
|
||||
const objectProperties = new gd.MapStringPropertyDescriptor();
|
||||
const objectContent = this.content;
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('text')
|
||||
@@ -66,13 +64,6 @@ module.exports = {
|
||||
.setLabel(_('Base color'))
|
||||
.setGroup(_('Appearance'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('opacity')
|
||||
.setValue(objectContent.opacity.toString())
|
||||
.setType('number')
|
||||
.setLabel(_('Opacity (0-255)'))
|
||||
.setGroup(_('Appearance'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('fontSize')
|
||||
.setValue(objectContent.fontSize.toString())
|
||||
@@ -114,29 +105,26 @@ module.exports = {
|
||||
|
||||
return objectProperties;
|
||||
};
|
||||
objectBBText.setRawJSONContent(
|
||||
JSON.stringify({
|
||||
text:
|
||||
'[b]bold[/b] [i]italic[/i] [size=15]smaller[/size] [font=times]times[/font] font\n[spacing=12]spaced out[/spacing]\n[outline=yellow]outlined[/outline] [shadow=red]DropShadow[/shadow] ',
|
||||
opacity: 255,
|
||||
fontSize: 20,
|
||||
visible: true,
|
||||
color: '0;0;0',
|
||||
fontFamily: 'Arial',
|
||||
align: 'left',
|
||||
wordWrap: true,
|
||||
})
|
||||
);
|
||||
objectBBText.content = {
|
||||
text:
|
||||
'[b]bold[/b] [i]italic[/i] [size=15]smaller[/size] [font=times]times[/font] font\n[spacing=12]spaced out[/spacing]\n[outline=yellow]outlined[/outline] [shadow=red]DropShadow[/shadow] ',
|
||||
opacity: 255,
|
||||
fontSize: 20,
|
||||
visible: true,
|
||||
color: '0;0;0',
|
||||
fontFamily: 'Arial',
|
||||
align: 'left',
|
||||
wordWrap: true,
|
||||
};
|
||||
|
||||
objectBBText.updateInitialInstanceProperty = function (
|
||||
objectContent,
|
||||
instance,
|
||||
propertyName,
|
||||
newValue
|
||||
) {
|
||||
return false;
|
||||
};
|
||||
objectBBText.getInitialInstanceProperties = function (content, instance) {
|
||||
objectBBText.getInitialInstanceProperties = function (instance) {
|
||||
var instanceProperties = new gd.MapStringPropertyDescriptor();
|
||||
return instanceProperties;
|
||||
};
|
||||
@@ -538,25 +526,33 @@ module.exports = {
|
||||
* This is called to update the PIXI object on the scene editor
|
||||
*/
|
||||
update() {
|
||||
const properties = this._associatedObjectConfiguration.getProperties();
|
||||
const object = gd.castObject(
|
||||
this._associatedObjectConfiguration,
|
||||
gd.ObjectJsImplementation
|
||||
);
|
||||
|
||||
const rawText = properties.get('text').getValue();
|
||||
const rawText = object.content.text;
|
||||
if (rawText !== this._pixiObject.text) {
|
||||
this._pixiObject.text = rawText;
|
||||
}
|
||||
|
||||
const opacity = +properties.get('opacity').getValue();
|
||||
this._pixiObject.alpha = opacity / 255;
|
||||
const color = object.content.color;
|
||||
const newColor = objectsRenderingService.rgbOrHexToHexNumber(color);
|
||||
if (newColor !== this._pixiObject.textStyles.default.fill) {
|
||||
this._pixiObject.textStyles.default.fill = newColor;
|
||||
this._pixiObject.dirty = true;
|
||||
}
|
||||
|
||||
const color = properties.get('color').getValue();
|
||||
this._pixiObject.textStyles.default.fill = objectsRenderingService.rgbOrHexToHexNumber(
|
||||
color
|
||||
);
|
||||
const fontSize = object.content.fontSize;
|
||||
const newDefaultFontsize = `${fontSize}px`;
|
||||
if (
|
||||
newDefaultFontsize !== this._pixiObject.textStyles.default.fontSize
|
||||
) {
|
||||
this._pixiObject.textStyles.default.fontSize = `${fontSize}px`;
|
||||
this._pixiObject.dirty = true;
|
||||
}
|
||||
|
||||
const fontSize = properties.get('fontSize').getValue();
|
||||
this._pixiObject.textStyles.default.fontSize = `${fontSize}px`;
|
||||
|
||||
const fontResourceName = properties.get('fontFamily').getValue();
|
||||
const fontResourceName = object.content.fontFamily;
|
||||
|
||||
if (this._fontResourceName !== fontResourceName) {
|
||||
this._fontResourceName = fontResourceName;
|
||||
@@ -577,13 +573,13 @@ module.exports = {
|
||||
});
|
||||
}
|
||||
|
||||
const wordWrap = properties.get('wordWrap').getValue() === 'true';
|
||||
const wordWrap = object.content.wordWrap;
|
||||
if (wordWrap !== this._pixiObject._style.wordWrap) {
|
||||
this._pixiObject._style.wordWrap = wordWrap;
|
||||
this._pixiObject.dirty = true;
|
||||
}
|
||||
|
||||
const align = properties.get('align').getValue();
|
||||
const align = object.content.align;
|
||||
if (align !== this._pixiObject._style.align) {
|
||||
this._pixiObject._style.align = align;
|
||||
this._pixiObject.dirty = true;
|
||||
@@ -607,6 +603,13 @@ module.exports = {
|
||||
this._pixiObject.dirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Do not hide completely an object so it can still be manipulated
|
||||
const alphaForDisplay = Math.max(
|
||||
this._instance.getOpacity() / 255,
|
||||
0.5
|
||||
);
|
||||
this._pixiObject.alpha = alphaForDisplay;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -192,6 +192,9 @@ namespace gdjs {
|
||||
250
|
||||
);
|
||||
}
|
||||
if (initialInstanceData.opacity !== undefined) {
|
||||
this.setOpacity(initialInstanceData.opacity);
|
||||
}
|
||||
}
|
||||
|
||||
onDestroyed(): void {
|
||||
|
@@ -34,11 +34,8 @@ module.exports = {
|
||||
.setIcon('JsPlatform/Extensions/bitmapfont32.png');
|
||||
|
||||
const bitmapTextObject = new gd.ObjectJsImplementation();
|
||||
bitmapTextObject.updateProperty = function (
|
||||
objectContent,
|
||||
propertyName,
|
||||
newValue
|
||||
) {
|
||||
bitmapTextObject.updateProperty = function (propertyName, newValue) {
|
||||
const objectContent = this.content;
|
||||
if (propertyName in objectContent) {
|
||||
if (typeof objectContent[propertyName] === 'boolean')
|
||||
objectContent[propertyName] = newValue === '1';
|
||||
@@ -50,8 +47,9 @@ module.exports = {
|
||||
|
||||
return false;
|
||||
};
|
||||
bitmapTextObject.getProperties = function (objectContent) {
|
||||
bitmapTextObject.getProperties = function () {
|
||||
const objectProperties = new gd.MapStringPropertyDescriptor();
|
||||
const objectContent = this.content;
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('text')
|
||||
@@ -59,13 +57,6 @@ module.exports = {
|
||||
.setType('textarea')
|
||||
.setLabel(_('Text'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('opacity')
|
||||
.setValue(objectContent.opacity.toString())
|
||||
.setType('number')
|
||||
.setLabel(_('Opacity (0-255)'))
|
||||
.setGroup(_('Appearance'));
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('align')
|
||||
.setValue(objectContent.align)
|
||||
@@ -73,7 +64,7 @@ module.exports = {
|
||||
.addExtraInfo('left')
|
||||
.addExtraInfo('center')
|
||||
.addExtraInfo('right')
|
||||
.setLabel(_('Alignment, when multiple lines are displayed'))
|
||||
.setLabel(_('Alignment'))
|
||||
.setGroup(_('Appearance'));
|
||||
|
||||
objectProperties
|
||||
@@ -89,7 +80,7 @@ module.exports = {
|
||||
.setValue(objectContent.textureAtlasResourceName)
|
||||
.setType('resource')
|
||||
.addExtraInfo('image')
|
||||
.setLabel(_('Bitmap atlas image'))
|
||||
.setLabel(_('Bitmap Atlas'))
|
||||
.setGroup(_('Font'));
|
||||
|
||||
objectProperties
|
||||
@@ -115,33 +106,27 @@ module.exports = {
|
||||
|
||||
return objectProperties;
|
||||
};
|
||||
bitmapTextObject.setRawJSONContent(
|
||||
JSON.stringify({
|
||||
text:
|
||||
'This text use the default bitmap font.\nUse a custom Bitmap Font to create your own texts.',
|
||||
opacity: 255,
|
||||
scale: 1,
|
||||
fontSize: 20,
|
||||
tint: '255;255;255',
|
||||
bitmapFontResourceName: '',
|
||||
textureAtlasResourceName: '',
|
||||
align: 'left',
|
||||
wordWrap: true,
|
||||
})
|
||||
);
|
||||
bitmapTextObject.content = {
|
||||
text:
|
||||
'This text use the default bitmap font.\nUse a custom Bitmap Font to create your own texts.',
|
||||
opacity: 255,
|
||||
scale: 1,
|
||||
fontSize: 20,
|
||||
tint: '255;255;255',
|
||||
bitmapFontResourceName: '',
|
||||
textureAtlasResourceName: '',
|
||||
align: 'left',
|
||||
wordWrap: true,
|
||||
};
|
||||
|
||||
bitmapTextObject.updateInitialInstanceProperty = function (
|
||||
objectContent,
|
||||
instance,
|
||||
propertyName,
|
||||
newValue
|
||||
) {
|
||||
return false;
|
||||
};
|
||||
bitmapTextObject.getInitialInstanceProperties = function (
|
||||
content,
|
||||
instance
|
||||
) {
|
||||
bitmapTextObject.getInitialInstanceProperties = function (instance) {
|
||||
var instanceProperties = new gd.MapStringPropertyDescriptor();
|
||||
return instanceProperties;
|
||||
};
|
||||
@@ -666,34 +651,31 @@ module.exports = {
|
||||
}
|
||||
|
||||
update() {
|
||||
const properties = this._associatedObjectConfiguration.getProperties();
|
||||
const object = gd.castObject(
|
||||
this._associatedObjectConfiguration,
|
||||
gd.ObjectJsImplementation
|
||||
);
|
||||
|
||||
// Update the rendered text properties (note: Pixi is only
|
||||
// applying changes if there were changed).
|
||||
const rawText = properties.get('text').getValue();
|
||||
const rawText = object.content.text;
|
||||
this._pixiObject.text = rawText;
|
||||
|
||||
const opacity = +properties.get('opacity').getValue();
|
||||
this._pixiObject.alpha = opacity / 255;
|
||||
|
||||
const align = properties.get('align').getValue();
|
||||
const align = object.content.align;
|
||||
this._pixiObject.align = align;
|
||||
|
||||
const color = properties.get('tint').getValue();
|
||||
const color = object.content.tint;
|
||||
this._pixiObject.tint = objectsRenderingService.rgbOrHexToHexNumber(
|
||||
color
|
||||
);
|
||||
|
||||
const scale = +(properties.get('scale').getValue() || 1);
|
||||
const scale = object.content.scale;
|
||||
this._pixiObject.scale.set(scale);
|
||||
|
||||
// Track the changes in font to load the new requested font.
|
||||
const bitmapFontResourceName = properties
|
||||
.get('bitmapFontResourceName')
|
||||
.getValue();
|
||||
const textureAtlasResourceName = properties
|
||||
.get('textureAtlasResourceName')
|
||||
.getValue();
|
||||
const bitmapFontResourceName = object.content.bitmapFontResourceName;
|
||||
const textureAtlasResourceName =
|
||||
object.content.textureAtlasResourceName;
|
||||
|
||||
if (
|
||||
this._currentBitmapFontResourceName !== bitmapFontResourceName ||
|
||||
@@ -722,7 +704,7 @@ module.exports = {
|
||||
}
|
||||
|
||||
// Set up the wrapping width if enabled.
|
||||
const wordWrap = properties.get('wordWrap').getValue() === 'true';
|
||||
const wordWrap = object.content.wordWrap;
|
||||
if (wordWrap && this._instance.hasCustomSize()) {
|
||||
this._pixiObject.maxWidth =
|
||||
this.getCustomWidth() / this._pixiObject.scale.x;
|
||||
@@ -739,6 +721,13 @@ module.exports = {
|
||||
this._pixiObject.rotation = RenderedInstance.toRad(
|
||||
this._instance.getAngle()
|
||||
);
|
||||
|
||||
// Do not hide completely an object so it can still be manipulated
|
||||
const alphaForDisplay = Math.max(
|
||||
this._instance.getOpacity() / 255,
|
||||
0.5
|
||||
);
|
||||
this._pixiObject.alpha = alphaForDisplay;
|
||||
}
|
||||
|
||||
onRemovedFromScene() {
|
||||
|
@@ -203,6 +203,9 @@ namespace gdjs {
|
||||
if (initialInstanceData.customSize) {
|
||||
this.setWrappingWidth(initialInstanceData.width);
|
||||
}
|
||||
if (initialInstanceData.opacity !== undefined) {
|
||||
this.setOpacity(initialInstanceData.opacity);
|
||||
}
|
||||
}
|
||||
|
||||
onDestroyed(): void {
|
||||
|
@@ -26,7 +26,8 @@ DestroyOutsideBehavior::GetProperties(
|
||||
behaviorContent.GetDoubleAttribute("extraBorder", 0)))
|
||||
.SetType("Number")
|
||||
.SetMeasurementUnit(gd::MeasurementUnit::GetPixel())
|
||||
.SetLabel(_("Margin before deleting the object, in pixels"));
|
||||
.SetLabel(_("Deletion margin"))
|
||||
.SetDescription(_("Margin before deleting the object, in pixels"));
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
@@ -26,7 +26,7 @@ std::map<gd::String, gd::PropertyDescriptor> DraggableBehavior::GetProperties(
|
||||
? "true"
|
||||
: "false")
|
||||
.SetType("Boolean")
|
||||
.SetLabel(_("Do a precision check against the object's collision mask"))
|
||||
.SetLabel(_("Precise check"))
|
||||
.SetDescription(
|
||||
_("Use the object (custom) collision mask instead of the bounding "
|
||||
"box, making the behavior more precise at the cost of "
|
||||
|
@@ -67,14 +67,10 @@ namespace gdjs {
|
||||
const bevelFilter = (filter as unknown) as PIXI.filters.BevelFilter &
|
||||
BevelFilterExtra;
|
||||
if (parameterName === 'lightColor') {
|
||||
bevelFilter.lightColor = gdjs.PixiFiltersTools.rgbOrHexToHexNumber(
|
||||
value
|
||||
);
|
||||
bevelFilter.lightColor = gdjs.rgbOrHexStringToNumber(value);
|
||||
}
|
||||
if (parameterName === 'shadowColor') {
|
||||
bevelFilter.shadowColor = gdjs.PixiFiltersTools.rgbOrHexToHexNumber(
|
||||
value
|
||||
);
|
||||
bevelFilter.shadowColor = gdjs.rgbOrHexStringToNumber(value);
|
||||
}
|
||||
}
|
||||
updateColorParameter(
|
||||
|
@@ -45,13 +45,9 @@ namespace gdjs {
|
||||
const colorReplaceFilter = (filter as unknown) as PIXI.filters.ColorReplaceFilter &
|
||||
ColorReplaceFilterExtra;
|
||||
if (parameterName === 'originalColor') {
|
||||
colorReplaceFilter.originalColor = gdjs.PixiFiltersTools.rgbOrHexToHexNumber(
|
||||
value
|
||||
);
|
||||
colorReplaceFilter.originalColor = gdjs.rgbOrHexStringToNumber(value);
|
||||
} else if (parameterName === 'newColor') {
|
||||
colorReplaceFilter.newColor = gdjs.PixiFiltersTools.rgbOrHexToHexNumber(
|
||||
value
|
||||
);
|
||||
colorReplaceFilter.newColor = gdjs.rgbOrHexStringToNumber(value);
|
||||
}
|
||||
}
|
||||
updateColorParameter(
|
||||
|
@@ -66,9 +66,7 @@ namespace gdjs {
|
||||
) {
|
||||
const dropShadowFilter = (filter as unknown) as PIXI.filters.DropShadowFilter;
|
||||
if (parameterName === 'color') {
|
||||
dropShadowFilter.color = gdjs.PixiFiltersTools.rgbOrHexToHexNumber(
|
||||
value
|
||||
);
|
||||
dropShadowFilter.color = gdjs.rgbOrHexStringToNumber(value);
|
||||
}
|
||||
}
|
||||
updateColorParameter(
|
||||
|
@@ -53,7 +53,7 @@ namespace gdjs {
|
||||
const glowFilter = (filter as unknown) as PIXI.filters.GlowFilter &
|
||||
GlowFilterExtra;
|
||||
if (parameterName === 'color') {
|
||||
glowFilter.color = gdjs.PixiFiltersTools.rgbOrHexToHexNumber(value);
|
||||
glowFilter.color = gdjs.rgbOrHexStringToNumber(value);
|
||||
}
|
||||
}
|
||||
updateColorParameter(
|
||||
|
@@ -41,9 +41,7 @@ namespace gdjs {
|
||||
) {
|
||||
const outlineFilter = (filter as unknown) as PIXI.filters.OutlineFilter;
|
||||
if (parameterName === 'color') {
|
||||
outlineFilter.color = gdjs.PixiFiltersTools.rgbOrHexToHexNumber(
|
||||
value
|
||||
);
|
||||
outlineFilter.color = gdjs.rgbOrHexStringToNumber(value);
|
||||
}
|
||||
}
|
||||
updateColorParameter(
|
||||
|
@@ -287,11 +287,9 @@ module.exports = {
|
||||
// Everything that is stored inside the object is in "content" and is automatically
|
||||
// saved/loaded to JSON.
|
||||
var dummyObject = new gd.ObjectJsImplementation();
|
||||
dummyObject.updateProperty = function (
|
||||
objectContent,
|
||||
propertyName,
|
||||
newValue
|
||||
) {
|
||||
dummyObject.updateProperty = function (propertyName, newValue) {
|
||||
const objectContent = this.content;
|
||||
|
||||
if (propertyName === 'My first property') {
|
||||
objectContent.property1 = newValue;
|
||||
return true;
|
||||
@@ -311,8 +309,9 @@ module.exports = {
|
||||
|
||||
return false;
|
||||
};
|
||||
dummyObject.getProperties = function (objectContent) {
|
||||
dummyObject.getProperties = function () {
|
||||
var objectProperties = new gd.MapStringPropertyDescriptor();
|
||||
const objectContent = this.content;
|
||||
|
||||
objectProperties
|
||||
.getOrCreate('My first property')
|
||||
@@ -336,17 +335,14 @@ module.exports = {
|
||||
|
||||
return objectProperties;
|
||||
};
|
||||
dummyObject.setRawJSONContent(
|
||||
JSON.stringify({
|
||||
property1: 'Hello world',
|
||||
property2: true,
|
||||
property3: 123,
|
||||
myImage: '',
|
||||
})
|
||||
);
|
||||
dummyObject.content = {
|
||||
property1: 'Hello world',
|
||||
property2: true,
|
||||
property3: 123,
|
||||
myImage: '',
|
||||
};
|
||||
|
||||
dummyObject.updateInitialInstanceProperty = function (
|
||||
objectContent,
|
||||
instance,
|
||||
propertyName,
|
||||
newValue
|
||||
@@ -362,7 +358,7 @@ module.exports = {
|
||||
|
||||
return false;
|
||||
};
|
||||
dummyObject.getInitialInstanceProperties = function (content, instance) {
|
||||
dummyObject.getInitialInstanceProperties = function (instance) {
|
||||
var instanceProperties = new gd.MapStringPropertyDescriptor();
|
||||
|
||||
instanceProperties
|
||||
@@ -507,12 +503,13 @@ module.exports = {
|
||||
* This is called to update the PIXI object on the scene editor
|
||||
*/
|
||||
update() {
|
||||
const object = gd.castObject(
|
||||
this._associatedObjectConfiguration,
|
||||
gd.ObjectJsImplementation
|
||||
);
|
||||
|
||||
// Read a property from the object
|
||||
const property1Value = this._associatedObjectConfiguration
|
||||
.getProperties()
|
||||
.get('My first property')
|
||||
.getValue();
|
||||
this._pixiObject.text = property1Value;
|
||||
this._pixiObject.text = object.content.property1;
|
||||
|
||||
// Read position and angle from the instance
|
||||
this._pixiObject.position.x =
|
||||
|
@@ -30,7 +30,13 @@ namespace gdjs {
|
||||
if (typeof firebaseConfig !== 'object') return;
|
||||
if (firebase.apps.length !== 0) await firebase.app().delete();
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
for (let func of onAppCreated) func();
|
||||
for (let func of onAppCreated) {
|
||||
try {
|
||||
func();
|
||||
} catch (e) {
|
||||
logger.error('An error occurred while running a callback: ' + e);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
gdjs.registerFirstRuntimeSceneLoadedCallback(_setupFirebase);
|
||||
|
@@ -68,11 +68,8 @@ module.exports = {
|
||||
|
||||
const lightObject = new gd.ObjectJsImplementation();
|
||||
|
||||
lightObject.updateProperty = function (
|
||||
objectContent,
|
||||
propertyName,
|
||||
newValue
|
||||
) {
|
||||
lightObject.updateProperty = function (propertyName, newValue) {
|
||||
const objectContent = this.content;
|
||||
if (propertyName === 'radius') {
|
||||
objectContent.radius = parseFloat(newValue);
|
||||
return true;
|
||||
@@ -96,8 +93,9 @@ module.exports = {
|
||||
return false;
|
||||
};
|
||||
|
||||
lightObject.getProperties = function (objectContent) {
|
||||
lightObject.getProperties = function () {
|
||||
const objectProperties = new gd.MapStringPropertyDescriptor();
|
||||
const objectContent = this.content;
|
||||
|
||||
objectProperties.set(
|
||||
'radius',
|
||||
@@ -140,17 +138,14 @@ module.exports = {
|
||||
|
||||
return objectProperties;
|
||||
};
|
||||
lightObject.setRawJSONContent(
|
||||
JSON.stringify({
|
||||
radius: 50,
|
||||
color: '255;255;255',
|
||||
debugMode: false,
|
||||
texture: '',
|
||||
})
|
||||
);
|
||||
lightObject.content = {
|
||||
radius: 50,
|
||||
color: '255;255;255',
|
||||
debugMode: false,
|
||||
texture: '',
|
||||
};
|
||||
|
||||
lightObject.updateInitialInstanceProperty = function (
|
||||
objectContent,
|
||||
instance,
|
||||
propertyName,
|
||||
newValue
|
||||
@@ -158,7 +153,7 @@ module.exports = {
|
||||
return false;
|
||||
};
|
||||
|
||||
lightObject.getInitialInstanceProperties = function (content, instance) {
|
||||
lightObject.getInitialInstanceProperties = function (instance) {
|
||||
const instanceProperties = new gd.MapStringPropertyDescriptor();
|
||||
|
||||
return instanceProperties;
|
||||
@@ -238,6 +233,10 @@ module.exports = {
|
||||
* Renderer for instances of LightObject inside the IDE.
|
||||
*/
|
||||
class RenderedLightObjectInstance extends RenderedInstance {
|
||||
_radius = 0;
|
||||
_color = 0;
|
||||
_radiusGraphics = null;
|
||||
|
||||
constructor(
|
||||
project,
|
||||
instance,
|
||||
@@ -252,19 +251,6 @@ module.exports = {
|
||||
pixiContainer,
|
||||
pixiResourcesLoader
|
||||
);
|
||||
this._radius = parseFloat(
|
||||
this._associatedObjectConfiguration
|
||||
.getProperties()
|
||||
.get('radius')
|
||||
.getValue()
|
||||
);
|
||||
if (this._radius <= 0) this._radius = 1;
|
||||
const color = objectsRenderingService.rgbOrHexToHexNumber(
|
||||
this._associatedObjectConfiguration
|
||||
.getProperties()
|
||||
.get('color')
|
||||
.getValue()
|
||||
);
|
||||
|
||||
// The icon in the middle.
|
||||
const lightIconSprite = new PIXI.Sprite(
|
||||
@@ -274,18 +260,11 @@ module.exports = {
|
||||
lightIconSprite.anchor.y = 0.5;
|
||||
|
||||
// The circle to show the radius of the light.
|
||||
const radiusBorderWidth = 2;
|
||||
const radiusGraphics = new PIXI.Graphics();
|
||||
radiusGraphics.lineStyle(radiusBorderWidth, color, 0.8);
|
||||
radiusGraphics.drawCircle(
|
||||
0,
|
||||
0,
|
||||
Math.max(1, this._radius - radiusBorderWidth)
|
||||
);
|
||||
this._radiusGraphics = new PIXI.Graphics();
|
||||
|
||||
this._pixiObject = new PIXI.Container();
|
||||
this._pixiObject.addChild(lightIconSprite);
|
||||
this._pixiObject.addChild(radiusGraphics);
|
||||
this._pixiObject.addChild(this._radiusGraphics);
|
||||
this._pixiContainer.addChild(this._pixiObject);
|
||||
this.update();
|
||||
}
|
||||
@@ -307,8 +286,41 @@ module.exports = {
|
||||
* This is called to update the PIXI object on the scene editor
|
||||
*/
|
||||
update() {
|
||||
const object = gd.castObject(
|
||||
this._associatedObjectConfiguration,
|
||||
gd.ObjectJsImplementation
|
||||
);
|
||||
|
||||
this._pixiObject.position.x = this._instance.getX();
|
||||
this._pixiObject.position.y = this._instance.getY();
|
||||
|
||||
let radiusGraphicsDirty = false;
|
||||
|
||||
let radius = object.content.radius;
|
||||
if (radius <= 0) radius = 1;
|
||||
if (radius !== this._radius) {
|
||||
this._radius = radius;
|
||||
radiusGraphicsDirty = true;
|
||||
}
|
||||
|
||||
const color = objectsRenderingService.rgbOrHexToHexNumber(
|
||||
object.content.color
|
||||
);
|
||||
if (color !== this._color) {
|
||||
this._color = color;
|
||||
radiusGraphicsDirty = true;
|
||||
}
|
||||
|
||||
if (radiusGraphicsDirty) {
|
||||
const radiusBorderWidth = 2;
|
||||
this._radiusGraphics.clear();
|
||||
this._radiusGraphics.lineStyle(radiusBorderWidth, color, 0.8);
|
||||
this._radiusGraphics.drawCircle(
|
||||
0,
|
||||
0,
|
||||
Math.max(1, this._radius - radiusBorderWidth)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -505,8 +505,9 @@ namespace gdjs {
|
||||
closestVertices.sort(
|
||||
LightRuntimeObjectPixiRenderer._verticesWithAngleComparator
|
||||
);
|
||||
const filteredVerticesResult = [closestVertices[0].vertex];
|
||||
const closestVerticesCount = closestVertices.length;
|
||||
if (closestVerticesCount === 0) return [];
|
||||
const filteredVerticesResult = [closestVertices[0].vertex];
|
||||
for (let i = 1; i < closestVerticesCount; i++) {
|
||||
if (closestVertices[i].angle !== closestVertices[i - 1].angle) {
|
||||
filteredVerticesResult.push(closestVertices[i].vertex);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user