mirror of
https://github.com/4ian/GDevelop.git
synced 2025-10-15 10:19:04 +00:00
Compare commits
11 Commits
v5.0.0-bet
...
v5.0.0-bet
Author | SHA1 | Date | |
---|---|---|---|
![]() |
1640ca49d7 | ||
![]() |
654b8d0bc1 | ||
![]() |
2a47d2f630 | ||
![]() |
e1423e0b90 | ||
![]() |
458430bbfb | ||
![]() |
2a5c18474e | ||
![]() |
827c53e9d5 | ||
![]() |
019920009a | ||
![]() |
aaed10a598 | ||
![]() |
193ce8bcf8 | ||
![]() |
fd020fd2a3 |
7
.github/workflows/issues.yml
vendored
7
.github/workflows/issues.yml
vendored
@@ -18,3 +18,10 @@ jobs:
|
||||
type: "body"
|
||||
regex: ".*Scroll down to '\\.\\.\\.\\.'.*"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed because it seems that you have not included any steps to reproduce the bug.\n\nGitHub is a place for the technical development of GDevelop itself - you may want to go on the [forum](https://forum.gdevelop-app.com/), the Discord chat or [read the documentation](http://wiki.compilgames.net/doku.php/gdevelop5/start) to learn more about GDevelop. Thanks!"
|
||||
- name: Autoclose known beta 105 web-app update bug
|
||||
uses: arkon/issue-closer-action@v1.1
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
type: "body"
|
||||
regex: ".*_instance.getRawFloatProperty is not a function.*"
|
||||
message: "Hi @${issue.user.login}! 👋 This issue was automatically closed as this seems to be a known bug. It can be solved by **closing entirely the web-app and opening it again**. This will allow the web-app to auto-update and the problem should be gone."
|
||||
|
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"type": "pwa-chrome",
|
||||
"request": "launch",
|
||||
"name": "Launch Chrome against localhost",
|
||||
"url": "http://localhost:3000",
|
||||
"webRoot": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
@@ -17,6 +17,7 @@ LayoutEditorCanvasOptions::LayoutEditorCanvasOptions()
|
||||
gridHeight(32),
|
||||
gridOffsetX(0),
|
||||
gridOffsetY(0),
|
||||
gridType("rectangular"),
|
||||
gridR(158),
|
||||
gridG(180),
|
||||
gridB(255),
|
||||
@@ -30,6 +31,7 @@ void LayoutEditorCanvasOptions::SerializeTo(SerializerElement& element) const {
|
||||
element.SetAttribute("gridHeight", gridHeight);
|
||||
element.SetAttribute("gridOffsetX", gridOffsetX);
|
||||
element.SetAttribute("gridOffsetY", gridOffsetY);
|
||||
element.SetAttribute("gridType", gridType);
|
||||
element.SetAttribute("gridR", gridR);
|
||||
element.SetAttribute("gridG", gridG);
|
||||
element.SetAttribute("gridB", gridB);
|
||||
@@ -42,10 +44,11 @@ void LayoutEditorCanvasOptions::UnserializeFrom(
|
||||
grid = element.GetBoolAttribute("grid");
|
||||
snap = element.GetBoolAttribute("snap");
|
||||
windowMask = element.GetBoolAttribute("windowMask");
|
||||
gridWidth = element.GetIntAttribute("gridWidth", 32);
|
||||
gridHeight = element.GetIntAttribute("gridHeight", 32);
|
||||
gridOffsetX = element.GetIntAttribute("gridOffsetX", 0);
|
||||
gridOffsetY = element.GetIntAttribute("gridOffsetY", 0);
|
||||
gridWidth = element.GetDoubleAttribute("gridWidth", 32);
|
||||
gridHeight = element.GetDoubleAttribute("gridHeight", 32);
|
||||
gridOffsetX = element.GetDoubleAttribute("gridOffsetX", 0);
|
||||
gridOffsetY = element.GetDoubleAttribute("gridOffsetY", 0);
|
||||
gridType = element.GetStringAttribute("gridType", "rectangular");
|
||||
gridR = element.GetIntAttribute("gridR", 158);
|
||||
gridG = element.GetIntAttribute("gridG", 180);
|
||||
gridB = element.GetIntAttribute("gridB", 255);
|
||||
|
@@ -40,10 +40,11 @@ class GD_CORE_API LayoutEditorCanvasOptions {
|
||||
|
||||
bool grid; ///< True if grid activated in editor
|
||||
bool snap; ///< True if snap to grid activated in editor
|
||||
int gridWidth; ///< Grid width in editor
|
||||
int gridHeight; ///< Grid height in editor
|
||||
int gridOffsetX; ///< Grid X offset
|
||||
int gridOffsetY; ///< Grid Y offset
|
||||
double gridWidth; ///< Grid width in editor
|
||||
double gridHeight; ///< Grid height in editor
|
||||
double gridOffsetX; ///< Grid X offset
|
||||
double gridOffsetY; ///< Grid Y offset
|
||||
gd::String gridType; ///< Grid type: rectangular or isometric
|
||||
int gridR; ///< Grid red color in editor
|
||||
int gridG; ///< Grid green color in editor
|
||||
int gridB; ///< Grid blue color in editor
|
||||
|
@@ -0,0 +1,78 @@
|
||||
describe('gdjs.PlatformerObjectRuntimeBehavior Benchmark', function () {
|
||||
let runtimeScene;
|
||||
let objects;
|
||||
const duplicateCount = 60;
|
||||
const stepCount = 6000;
|
||||
|
||||
beforeEach(function () {
|
||||
runtimeScene = makeTestRuntimeScene();
|
||||
|
||||
objects = new Array(duplicateCount);
|
||||
for (let i = 0; i < duplicateCount; ++i) {
|
||||
// Put a platformer object on a platform
|
||||
object = new gdjs.RuntimeObject(runtimeScene, {
|
||||
name: 'obj1',
|
||||
type: '',
|
||||
behaviors: [
|
||||
{
|
||||
type: 'PlatformBehavior::PlatformerObjectBehavior',
|
||||
name: 'auto1',
|
||||
gravity: 1500,
|
||||
maxFallingSpeed: 1500,
|
||||
acceleration: 500,
|
||||
deceleration: 1500,
|
||||
maxSpeed: 500,
|
||||
jumpSpeed: 900,
|
||||
canGrabPlatforms: true,
|
||||
ignoreDefaultControls: true,
|
||||
slopeMaxAngle: 60,
|
||||
jumpSustainTime: 0.2,
|
||||
roundCoordinates: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
object.getWidth = function () {
|
||||
return 10;
|
||||
};
|
||||
object.getHeight = function () {
|
||||
return 20;
|
||||
};
|
||||
runtimeScene.addObject(object);
|
||||
object.setPosition(100 * i + 60 * 5, 400 * i - 32);
|
||||
objects[i] = object;
|
||||
|
||||
// Put a platform.
|
||||
for (let p = 0; p < 10; ++p) {
|
||||
const platform = addPlatformObject(runtimeScene);
|
||||
platform.setPosition(100 * i + p * platform.getWidth(), 400 * i - 10);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('benchmark', function () {
|
||||
this.timeout(30000);
|
||||
|
||||
for (let b = 0; b < 10; ++b) {
|
||||
const benchmarkSuite = makeBenchmarkSuite({
|
||||
benchmarksCount: 1,
|
||||
iterationsCount: stepCount,
|
||||
});
|
||||
benchmarkSuite.add('jump in loop', (t) => {
|
||||
for (let i = 0; i < duplicateCount; ++i) {
|
||||
const object = objects[i];
|
||||
if (t % 60 == i % 60) {
|
||||
object.getBehavior('auto1').simulateJumpKey();
|
||||
}
|
||||
if (t + (i % 61) < 31) {
|
||||
object.getBehavior('auto1').simulateRightKey();
|
||||
}
|
||||
if (t + (i % 61) >= 31) {
|
||||
object.getBehavior('auto1').simulateLeftKey();
|
||||
}
|
||||
}
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
});
|
||||
console.log(benchmarkSuite.run());
|
||||
}
|
||||
});
|
||||
});
|
@@ -1357,7 +1357,9 @@ namespace gdjs {
|
||||
this._behavior = behavior;
|
||||
}
|
||||
|
||||
enter() {}
|
||||
enter() {
|
||||
this._behavior._canJump = false;
|
||||
}
|
||||
|
||||
leave() {}
|
||||
|
||||
|
@@ -471,6 +471,35 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
||||
expect(object.getY()).to.be(-30);
|
||||
});
|
||||
|
||||
it('should not jump after falling from a platform', function () {
|
||||
// Ensure the object falls on the platform
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
}
|
||||
|
||||
// Check the object is on the platform
|
||||
// So at this point, the object could jump
|
||||
expect(object.getY()).to.be(-30); // -30 = -10 (platform y) + -20 (object height)
|
||||
expect(object.getBehavior('auto1').isFalling()).to.be(false);
|
||||
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(
|
||||
false
|
||||
);
|
||||
expect(object.getBehavior('auto1').isMoving()).to.be(false);
|
||||
|
||||
// Fell from the platform
|
||||
for (let i = 0; i < 35; ++i) {
|
||||
object.getBehavior('auto1').simulateLeftKey();
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
}
|
||||
|
||||
// Try to jump
|
||||
object.getBehavior('auto1').simulateJumpKey();
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
expect(object.getBehavior('auto1').isJumping()).to.be(false);
|
||||
expect(object.getBehavior('auto1').isFalling()).to.be(true);
|
||||
expect(object.getBehavior('auto1').isFallingWithoutJumping()).to.be(true);
|
||||
});
|
||||
|
||||
it('should not grab a platform while in the ascending phase of a jump', function () {
|
||||
const topPlatform = addPlatformObject(runtimeScene);
|
||||
topPlatform.setPosition(12, -80);
|
||||
@@ -1576,83 +1605,4 @@ describe('gdjs.PlatformerObjectRuntimeBehavior', function () {
|
||||
expect(object.getY()).to.be.below(platform.getY());
|
||||
});
|
||||
});
|
||||
|
||||
describe.skip('(benchmark)', function () {
|
||||
let runtimeScene;
|
||||
let objects;
|
||||
const duplicateCount = 60;
|
||||
const stepCount = 6000;
|
||||
|
||||
beforeEach(function () {
|
||||
runtimeScene = makeTestRuntimeScene();
|
||||
|
||||
objects = new Array(duplicateCount);
|
||||
for (let i = 0; i < duplicateCount; ++i) {
|
||||
// Put a platformer object on a platform
|
||||
object = new gdjs.RuntimeObject(runtimeScene, {
|
||||
name: 'obj1',
|
||||
type: '',
|
||||
behaviors: [
|
||||
{
|
||||
type: 'PlatformBehavior::PlatformerObjectBehavior',
|
||||
name: 'auto1',
|
||||
gravity: 1500,
|
||||
maxFallingSpeed: 1500,
|
||||
acceleration: 500,
|
||||
deceleration: 1500,
|
||||
maxSpeed: 500,
|
||||
jumpSpeed: 900,
|
||||
canGrabPlatforms: true,
|
||||
ignoreDefaultControls: true,
|
||||
slopeMaxAngle: 60,
|
||||
jumpSustainTime: 0.2,
|
||||
roundCoordinates: true,
|
||||
},
|
||||
],
|
||||
});
|
||||
object.getWidth = function () {
|
||||
return 10;
|
||||
};
|
||||
object.getHeight = function () {
|
||||
return 20;
|
||||
};
|
||||
runtimeScene.addObject(object);
|
||||
object.setPosition(100 * i + 60 * 5, 400 * i - 32);
|
||||
objects[i] = object;
|
||||
|
||||
// Put a platform.
|
||||
for (let p = 0; p < 10; ++p) {
|
||||
const platform = addPlatformObject(runtimeScene);
|
||||
platform.setPosition(100 * i + p * platform.getWidth(), 400 * i - 10);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('benchmark', function () {
|
||||
this.timeout(30000);
|
||||
|
||||
for (let b = 0; b < 10; ++b) {
|
||||
const benchmarkSuite = makeBenchmarkSuite({
|
||||
benchmarksCount: 1,
|
||||
iterationsCount: stepCount,
|
||||
});
|
||||
benchmarkSuite.add('jump in loop', (t) => {
|
||||
for (let i = 0; i < duplicateCount; ++i) {
|
||||
const object = objects[i];
|
||||
if (t % 60 == i % 60) {
|
||||
object.getBehavior('auto1').simulateJumpKey();
|
||||
}
|
||||
if (t + (i % 61) < 31) {
|
||||
object.getBehavior('auto1').simulateRightKey();
|
||||
}
|
||||
if (t + (i % 61) >= 31) {
|
||||
object.getBehavior('auto1').simulateLeftKey();
|
||||
}
|
||||
}
|
||||
runtimeScene.renderAndStep(1000 / 60);
|
||||
});
|
||||
console.log(benchmarkSuite.run());
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@@ -347,11 +347,22 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
[](gd::BaseEvent& event_,
|
||||
gd::EventsCodeGenerator& codeGenerator,
|
||||
gd::EventsCodeGenerationContext& parentContext) {
|
||||
gd::String outputCode;
|
||||
gd::WhileEvent& event = dynamic_cast<gd::WhileEvent&>(event_);
|
||||
|
||||
// Context is "reset" each time the event is repeated (i.e. objects are
|
||||
// picked again)
|
||||
// Prevent code generation if the event is empty, as this would
|
||||
// get the game stuck in a never ending loop.
|
||||
if (
|
||||
event.GetWhileConditions().empty() &&
|
||||
event.GetConditions().empty() &&
|
||||
event.GetActions().empty()
|
||||
)
|
||||
return gd::String(
|
||||
"\n// While event not generated to prevent an infinite loop.\n");
|
||||
|
||||
gd::String outputCode;
|
||||
|
||||
// Context is "reset" each time the event is repeated (i.e. objects
|
||||
// are picked again)
|
||||
gd::EventsCodeGenerationContext context;
|
||||
context.InheritsFrom(parentContext);
|
||||
context.ForbidReuse();
|
||||
@@ -459,10 +470,12 @@ CommonInstructionsExtension::CommonInstructionsExtension() {
|
||||
// Define references to variables (if they exist)
|
||||
if (keyIteratorExists)
|
||||
outputCode +=
|
||||
"const $KEY_ITERATOR_REFERENCE = $KEY_ITERATOR_VARIABLE_ACCESSOR;\n";
|
||||
"const $KEY_ITERATOR_REFERENCE = "
|
||||
"$KEY_ITERATOR_VARIABLE_ACCESSOR;\n";
|
||||
if (valueIteratorExists)
|
||||
outputCode +=
|
||||
"const $VALUE_ITERATOR_REFERENCE = $VALUE_ITERATOR_VARIABLE_ACCESSOR;\n";
|
||||
"const $VALUE_ITERATOR_REFERENCE = "
|
||||
"$VALUE_ITERATOR_VARIABLE_ACCESSOR;\n";
|
||||
outputCode +=
|
||||
"const $ITERABLE_REFERENCE = $ITERABLE_VARIABLE_ACCESSOR;\n";
|
||||
|
||||
|
@@ -168,11 +168,13 @@ namespace gdjs {
|
||||
) {
|
||||
if (obj === null) {
|
||||
variable.setString('null');
|
||||
} else if (
|
||||
(typeof obj === 'number' || typeof obj === 'string') &&
|
||||
!isNaN(obj as number)
|
||||
) {
|
||||
variable.setNumber(obj as number);
|
||||
} else if (typeof obj === 'number') {
|
||||
if (Number.isNaN(obj)) {
|
||||
console.warn('Variables cannot be set to NaN, setting it to 0.');
|
||||
variable.setNumber(0);
|
||||
} else {
|
||||
variable.setNumber(obj);
|
||||
}
|
||||
} else if (typeof obj === 'string') {
|
||||
variable.setString(obj);
|
||||
} else if (typeof obj === 'undefined') {
|
||||
@@ -195,9 +197,6 @@ namespace gdjs {
|
||||
}
|
||||
} else if (typeof obj === 'symbol') {
|
||||
variable.setString(obj.toString());
|
||||
} else if (typeof obj === 'number' && isNaN(obj)) {
|
||||
console.warn('Variables cannot be set to NaN, setting it to 0.');
|
||||
variable.setNumber(0);
|
||||
} else if (typeof obj === 'bigint') {
|
||||
if (obj > Number.MAX_SAFE_INTEGER)
|
||||
console.warn(
|
||||
|
@@ -239,7 +239,7 @@ namespace gdjs {
|
||||
},
|
||||
setValue: () => {},
|
||||
getValue: () => 0,
|
||||
getChild: () => gdjs.VariablesContainer.badVariable,
|
||||
getChild: () => gdjs.VariablesContainer.badVariable,
|
||||
getChildAt: () => gdjs.VariablesContainer.badVariable,
|
||||
hasChild: function () {
|
||||
return false;
|
||||
|
@@ -28,7 +28,7 @@
|
||||
"scripts": {
|
||||
"check-types": "tsc",
|
||||
"build": "node scripts/build.js",
|
||||
"test": "cd tests && npm test",
|
||||
"test": "cd tests && npm run test-benchmark",
|
||||
"format": "prettier --write \"Runtime/**/*.ts\" \"../Extensions/**/*.ts\" \"../Extensions/**/*.spec.js\"",
|
||||
"check-format": "prettier --list-different \"Runtime/**/*.ts\" \"../Extensions/**/*.ts\" \"../Extensions/**/*.spec.js\"",
|
||||
"generate-doc": "jsdoc -c docs/jsdoc.conf.json docs/DocMainPage.md"
|
||||
|
@@ -12,10 +12,13 @@ npm install
|
||||
Then launch tests:
|
||||
|
||||
```bash
|
||||
npm test #This will use Chrome Headless
|
||||
npm test:firefox #To run tests using Firefox
|
||||
npm run test:watch # This will use Chrome Headless
|
||||
npm run test-benchmark:watch # This will also run benchmarks
|
||||
npm run test:firefox:watch # To run tests using Firefox
|
||||
```
|
||||
|
||||
> ⚠️ If you're working on GDJS or extensions, make sure to have the development version of GDevelop running so that changes in GDJS or extension files are rebuilt (or run `npm run build` in `GDJS/`, but better run GDevelop so that any changes are watched).
|
||||
|
||||
## About the tests
|
||||
|
||||
### Unit tests
|
||||
|
@@ -1,4 +1,15 @@
|
||||
module.exports = function(config) {
|
||||
const testFiles = [
|
||||
'../../Extensions/**/tests/**.spec.js',
|
||||
'./tests/**/*.js',
|
||||
];
|
||||
|
||||
const benchmarkFiles = [
|
||||
'./benchmarks/init.js',
|
||||
'../../Extensions/**/benchmark/**.benchmark.js',
|
||||
'./benchmarks/**/*.js',
|
||||
];
|
||||
|
||||
config.set({
|
||||
frameworks: ['mocha'],
|
||||
browserNoActivityTimeout: 400000,
|
||||
@@ -63,15 +74,12 @@ module.exports = function(config) {
|
||||
|
||||
//All tests files:
|
||||
'./tests-utils/init.pixiruntimegamewithassets.js',
|
||||
'../../Extensions/**/tests/**.spec.js',
|
||||
'./tests/**/*.js',
|
||||
|
||||
//All benchmark files:
|
||||
'./benchmarks/init.js',
|
||||
'./benchmarks/**/*.js',
|
||||
|
||||
// Assets
|
||||
{pattern: './tests-utils/assets/*.jpg', watched: false, included: false, served: true, nocache: false}
|
||||
{pattern: './tests-utils/assets/*.jpg', watched: false, included: false, served: true, nocache: false},
|
||||
|
||||
...testFiles,
|
||||
...(config.enableBenchmarks ? benchmarkFiles : [])
|
||||
]
|
||||
});
|
||||
};
|
||||
|
@@ -7,6 +7,8 @@
|
||||
"scripts": {
|
||||
"test": "karma start --browsers ChromeHeadless --single-run",
|
||||
"test:watch": "karma start --browsers ChromeHeadless",
|
||||
"test-benchmark": "karma start --browsers ChromeHeadless --single-run --enableBenchmarks",
|
||||
"test-benchmark:watch": "karma start --browsers ChromeHeadless --enableBenchmarks",
|
||||
"test:firefox": "karma start --browsers Firefox --single-run",
|
||||
"test:firefox:watch": "karma start --browsers Firefox"
|
||||
},
|
||||
|
@@ -126,7 +126,11 @@ describe('gdjs.Variable', function () {
|
||||
|
||||
it('can be serialized to JSON', function () {
|
||||
var structure = new gdjs.Variable({ value: '0' });
|
||||
|
||||
// Verify numbers serialization
|
||||
structure.getChild('a').setNumber(5);
|
||||
|
||||
// Verify structures serialization
|
||||
structure.getChild('b').getChild('alpha').setString('Apples');
|
||||
structure.getChild('b').getChild('beta').setBoolean(true);
|
||||
structure
|
||||
@@ -135,15 +139,24 @@ describe('gdjs.Variable', function () {
|
||||
.setString(
|
||||
'String with quotes "", and a backslash \\ and new line \\n \\n\\r and brackets {[{}]}!'
|
||||
);
|
||||
|
||||
// Verify array serialization
|
||||
const array = structure.getChild('c');
|
||||
array.castTo('array');
|
||||
array.pushValue(49);
|
||||
array.pushVariableCopy(structure.getChild('b'));
|
||||
|
||||
// Verify empty string serialization
|
||||
structure.getChild('d').setString("");
|
||||
|
||||
// Verify boolean serialization
|
||||
structure.getChild('e').setBoolean(false);
|
||||
structure.getChild('f').setBoolean(true);
|
||||
|
||||
const b =
|
||||
'{"alpha": "Apples","beta": true,"Child with quotes \\"\\" and a backlash \\\\": "String with quotes \\"\\", and a backslash \\\\ and new line \\\\n \\\\n\\\\r and brackets {[{}]}!"}';
|
||||
expect(gdjs.evtTools.network.variableStructureToJSON(structure)).to.be(
|
||||
`{"a": 5,"b": ${b},"c": [49,${b}]}`
|
||||
`{"a": 5,"b": ${b},"c": [49,${b}],"d": "","e": false,"f": true}`
|
||||
);
|
||||
});
|
||||
|
||||
@@ -153,7 +166,7 @@ describe('gdjs.Variable', function () {
|
||||
'{"alpha": "Apples","beta": true,"Child with quotes \\"\\" and a backlash \\\\": "String with quotes \\"\\", and a backslash \\\\ and new line \\\\n \\\\n\\\\r and brackets {[{}]}!"}';
|
||||
|
||||
gdjs.evtTools.network.jsonToVariableStructure(
|
||||
`{"a": 5,"b": ${b},"c": [49,${b}]}`,
|
||||
`{"a": 5,"b": ${b},"c": [49,${b}],"d": "","e": false, "f": true}`,
|
||||
structure
|
||||
);
|
||||
|
||||
@@ -187,6 +200,15 @@ describe('gdjs.Variable', function () {
|
||||
).to.be(
|
||||
'String with quotes "", and a backslash \\ and new line \\n \\n\\r and brackets {[{}]}!'
|
||||
);
|
||||
|
||||
expect(structure.getChild('d').getType()).to.be('string');
|
||||
expect(structure.getChild('d').getAsString()).to.be('');
|
||||
|
||||
expect(structure.getChild('e').getType()).to.be('boolean');
|
||||
expect(structure.getChild('e').getAsBoolean()).to.be(false);
|
||||
|
||||
expect(structure.getChild('f').getType()).to.be('boolean');
|
||||
expect(structure.getChild('f').getAsBoolean()).to.be(true);
|
||||
});
|
||||
it('exposes a badVariable that is neutral for all operations', function () {
|
||||
expect(gdjs.VariablesContainer.badVariable.getValue()).to.be(0);
|
||||
|
@@ -5,21 +5,26 @@ const fs = require('fs');
|
||||
const shell = require('shelljs');
|
||||
const readThemeRegistry = require('./lib/ReadThemeRegistry');
|
||||
|
||||
let theme = args[2];
|
||||
if (!theme) {
|
||||
let themeName = args[2];
|
||||
if (!themeName) {
|
||||
shell.echo('❌ Please enter a theme name');
|
||||
}
|
||||
|
||||
if (!theme.toLowerCase().endsWith('theme')) {
|
||||
theme = theme + 'Theme';
|
||||
if (themeName.toLowerCase().endsWith('theme')) {
|
||||
// Remove unnecessary trailing "Theme" from input
|
||||
// eg: "Foo Bar" => "Foo Bar", "Foo Theme" => "Foo", "FooTheme" => "Foo"
|
||||
const lastIndex = themeName.toLowerCase().lastIndexOf('theme');
|
||||
themeName = themeName.slice(0, lastIndex).trim();
|
||||
}
|
||||
|
||||
const themeId = theme.replace(/\s+/, '');
|
||||
// Remove spaces and append 'Theme' to get full theme identifier
|
||||
// eg: "Foo Bar" => "FooBarTheme"
|
||||
const themeId = themeName.replace(/\s+/, '') + 'Theme';
|
||||
|
||||
|
||||
const dir = path.resolve(__dirname, '../src/UI/Theme/', themeId);
|
||||
if (fs.existsSync(dir)) {
|
||||
shell.echo('❌ Theme `' + theme + '` already exists');
|
||||
shell.echo('❌ Theme `' + themeName + '` already exists');
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
@@ -45,7 +50,7 @@ shell.echo('✅ Created index.js');
|
||||
const registry = readThemeRegistry()
|
||||
.concat({
|
||||
id: themeId,
|
||||
name: theme,
|
||||
name: themeName,
|
||||
});
|
||||
|
||||
const imports =
|
||||
|
@@ -1,4 +1,4 @@
|
||||
import { createGdevelopTheme } from '../theme';
|
||||
import { createGdevelopTheme } from '../CreateTheme';
|
||||
|
||||
import styles from './$THEME_IDVariables.json';
|
||||
import './$THEME_IDVariables.css';
|
||||
|
399
newIDE/app/src/CodeEditor/Theme/OneDark.js
Normal file
399
newIDE/app/src/CodeEditor/Theme/OneDark.js
Normal file
@@ -0,0 +1,399 @@
|
||||
const themeData = {
|
||||
base: 'vs-dark',
|
||||
inherit: true,
|
||||
rules: [
|
||||
{
|
||||
foreground: 'abb2bf',
|
||||
token: 'text',
|
||||
},
|
||||
{
|
||||
foreground: 'abb2bf',
|
||||
token: 'source',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token: 'variable.parameter.function',
|
||||
},
|
||||
{
|
||||
foreground: '5f697a',
|
||||
fontStyle: ' italic',
|
||||
token: 'comment',
|
||||
},
|
||||
{
|
||||
foreground: '5f697a',
|
||||
fontStyle: ' italic',
|
||||
token: 'punctuation.definition.comment',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token: 'none',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token: 'keyword.operator',
|
||||
},
|
||||
{
|
||||
foreground: 'cd74e8',
|
||||
token: 'keyword',
|
||||
},
|
||||
{
|
||||
foreground: 'eb6772',
|
||||
token: 'variable',
|
||||
},
|
||||
{
|
||||
foreground: '5cb3fa',
|
||||
token: 'entity.name.function',
|
||||
},
|
||||
{
|
||||
foreground: '5cb3fa',
|
||||
token: 'meta.require',
|
||||
},
|
||||
{
|
||||
foreground: '5cb3fa',
|
||||
token: 'support.function.any-method',
|
||||
},
|
||||
{
|
||||
foreground: 'f0c678',
|
||||
token: 'support.class',
|
||||
},
|
||||
{
|
||||
foreground: 'f0c678',
|
||||
token: 'entity.name.class',
|
||||
},
|
||||
{
|
||||
foreground: 'f0c678',
|
||||
token: 'entity.name.type.class',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token: 'meta.class',
|
||||
},
|
||||
{
|
||||
foreground: '5cb3fa',
|
||||
token: 'keyword.other.special-method',
|
||||
},
|
||||
{
|
||||
foreground: 'cd74e8',
|
||||
token: 'storage',
|
||||
},
|
||||
{
|
||||
foreground: '5ebfcc',
|
||||
token: 'support.function',
|
||||
},
|
||||
{
|
||||
foreground: '9acc76',
|
||||
token: 'string',
|
||||
},
|
||||
{
|
||||
foreground: '9acc76',
|
||||
token: 'constant.other.symbol',
|
||||
},
|
||||
{
|
||||
foreground: '9acc76',
|
||||
token: 'entity.other.inherited-class',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'constant.numeric',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'none',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'none',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'constant',
|
||||
},
|
||||
{
|
||||
foreground: 'eb6772',
|
||||
token: 'entity.name.tag',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'entity.other.attribute-name',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'entity.other.attribute-name.id',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'punctuation.definition.entity',
|
||||
},
|
||||
{
|
||||
foreground: 'cd74e8',
|
||||
token: 'meta.selector',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'none',
|
||||
},
|
||||
{
|
||||
foreground: '5cb3fa',
|
||||
token: 'markup.heading punctuation.definition.heading',
|
||||
},
|
||||
{
|
||||
foreground: '5cb3fa',
|
||||
token: 'entity.name.section',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'keyword.other.unit',
|
||||
},
|
||||
{
|
||||
foreground: 'f0c678',
|
||||
token: 'markup.bold',
|
||||
},
|
||||
{
|
||||
foreground: 'f0c678',
|
||||
token: 'punctuation.definition.bold',
|
||||
},
|
||||
{
|
||||
foreground: 'cd74e8',
|
||||
token: 'markup.italic',
|
||||
},
|
||||
{
|
||||
foreground: 'cd74e8',
|
||||
token: 'punctuation.definition.italic',
|
||||
},
|
||||
{
|
||||
foreground: '9acc76',
|
||||
token: 'markup.raw.inline',
|
||||
},
|
||||
{
|
||||
foreground: 'eb6772',
|
||||
token: 'string.other.link',
|
||||
},
|
||||
{
|
||||
foreground: 'eb6772',
|
||||
token: 'punctuation.definition.string.end.markdown',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'meta.link',
|
||||
},
|
||||
{
|
||||
foreground: 'eb6772',
|
||||
token: 'markup.list',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'markup.quote',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
background: '515151',
|
||||
token: 'meta.separator',
|
||||
},
|
||||
{
|
||||
foreground: '9acc76',
|
||||
token: 'markup.inserted',
|
||||
},
|
||||
{
|
||||
foreground: 'eb6772',
|
||||
token: 'markup.deleted',
|
||||
},
|
||||
{
|
||||
foreground: 'cd74e8',
|
||||
token: 'markup.changed',
|
||||
},
|
||||
{
|
||||
foreground: '5ebfcc',
|
||||
token: 'constant.other.color',
|
||||
},
|
||||
{
|
||||
foreground: '5ebfcc',
|
||||
token: 'string.regexp',
|
||||
},
|
||||
{
|
||||
foreground: '5ebfcc',
|
||||
token: 'constant.character.escape',
|
||||
},
|
||||
{
|
||||
foreground: 'c94e42',
|
||||
token: 'punctuation.section.embedded',
|
||||
},
|
||||
{
|
||||
foreground: 'c94e42',
|
||||
token: 'variable.interpolation',
|
||||
},
|
||||
{
|
||||
foreground: 'ffffff',
|
||||
background: 'e05252',
|
||||
token: 'invalid.illegal',
|
||||
},
|
||||
{
|
||||
foreground: '2d2d2d',
|
||||
background: 'f99157',
|
||||
token: 'invalid.broken',
|
||||
},
|
||||
{
|
||||
foreground: '2c323d',
|
||||
background: 'd27b53',
|
||||
token: 'invalid.deprecated',
|
||||
},
|
||||
{
|
||||
foreground: '2c323d',
|
||||
background: '747369',
|
||||
token: 'invalid.unimplemented',
|
||||
},
|
||||
{
|
||||
foreground: 'eb6772',
|
||||
token:
|
||||
'source.json meta.structure.dictionary.json string.quoted.double.json',
|
||||
},
|
||||
{
|
||||
foreground: '9acc76',
|
||||
token:
|
||||
'source.json meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json',
|
||||
},
|
||||
{
|
||||
foreground: 'eb6772',
|
||||
token:
|
||||
'source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json string.quoted.double.json',
|
||||
},
|
||||
{
|
||||
foreground: '9acc76',
|
||||
token:
|
||||
'source.json meta.structure.dictionary.json meta.structure.dictionary.value.json meta.structure.dictionary.json meta.structure.dictionary.value.json string.quoted.double.json',
|
||||
},
|
||||
{
|
||||
foreground: 'cd74e8',
|
||||
token:
|
||||
'text.html.laravel-blade source.php.embedded.line.html entity.name.tag.laravel-blade',
|
||||
},
|
||||
{
|
||||
foreground: 'cd74e8',
|
||||
token:
|
||||
'text.html.laravel-blade source.php.embedded.line.html support.constant.laravel-blade',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token:
|
||||
'source.python meta.function.python meta.function.parameters.python variable.parameter.function.python',
|
||||
},
|
||||
{
|
||||
foreground: '5ebfcc',
|
||||
token: 'source.python meta.function-call.python support.type.python',
|
||||
},
|
||||
{
|
||||
foreground: 'cd74e8',
|
||||
token: 'source.python keyword.operator.logical.python',
|
||||
},
|
||||
{
|
||||
foreground: 'f0c678',
|
||||
token:
|
||||
'source.python meta.class.python punctuation.definition.inheritance.begin.python',
|
||||
},
|
||||
{
|
||||
foreground: 'f0c678',
|
||||
token:
|
||||
'source.python meta.class.python punctuation.definition.inheritance.end.python',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token:
|
||||
'source.python meta.function-call.python meta.function-call.arguments.python variable.parameter.function.python',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token:
|
||||
'text.html.basic source.php.embedded.block.html support.constant.std.php',
|
||||
},
|
||||
{
|
||||
foreground: 'f0c678',
|
||||
token:
|
||||
'text.html.basic source.php.embedded.block.html meta.namespace.php entity.name.type.namespace.php',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token: 'source.js meta.function.js support.constant.js',
|
||||
},
|
||||
{
|
||||
foreground: 'cd74e8',
|
||||
token:
|
||||
'text.html.basic` source.php.embedded.block.html constant.other.php',
|
||||
},
|
||||
{
|
||||
foreground: 'db9d63',
|
||||
token:
|
||||
'text.html.basic source.php.embedded.block.html support.other.namespace.php',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token:
|
||||
'text.tex.latex meta.function.environment.math.latex string.other.math.block.environment.latex meta.definition.label.latex variable.parameter.definition.label.latex',
|
||||
},
|
||||
{
|
||||
foreground: 'cd74e8',
|
||||
fontStyle: ' italic',
|
||||
token: 'text.tex.latex meta.function.emph.latex markup.italic.emph.latex',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token: 'source.js variable.other.readwrite.js',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token:
|
||||
'source.js meta.function-call.with-arguments.js variable.function.js',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token:
|
||||
'source.js meta.group.braces.round meta.group.braces.curly meta.function-call.method.without-arguments.js variable.function.js',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token:
|
||||
'source.js meta.group.braces.round meta.group.braces.curly variable.other.object.js',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token:
|
||||
'source.js meta.group.braces.round meta.group.braces.curly constant.other.object.key.js string.unquoted.label.js',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token:
|
||||
'source.js meta.group.braces.round meta.group.braces.curly constant.other.object.key.js punctuation.separator.key-value.js',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token:
|
||||
'source.js meta.group.braces.round meta.group.braces.curly meta.function-call.method.with-arguments.js variable.function.js',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token:
|
||||
'source.js meta.function-call.method.with-arguments.js variable.function.js',
|
||||
},
|
||||
{
|
||||
foreground: 'adb7c9',
|
||||
token:
|
||||
'source.js meta.function-call.method.without-arguments.js variable.function.js',
|
||||
},
|
||||
],
|
||||
colors: {
|
||||
'editor.foreground': '#6c7079',
|
||||
'editor.background': '#2B303B',
|
||||
'editor.selectionBackground': '#bbccf51b',
|
||||
'editor.inactiveSelectionBackground': '#bbccf51b',
|
||||
'editor.lineHighlightBackground': '#8cc2fc0b',
|
||||
'editorCursor.foreground': '#528bff',
|
||||
'editorWhitespace.foreground': '#747369',
|
||||
'editorIndentGuide.background': '#464c55',
|
||||
'editorIndentGuide.activeBackground': '#464c55',
|
||||
'editor.selectionHighlightBorder': '#bbccf51b',
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
name: 'One-Dark',
|
||||
themeName: 'one-dark',
|
||||
themeData,
|
||||
};
|
@@ -7,6 +7,7 @@ import SolarizedLight from './SolarizedLight';
|
||||
import VibrantInk from './VibrantInk';
|
||||
import GitHub from './GitHub';
|
||||
import NordDark from './NordDark';
|
||||
import OneDark from './OneDark';
|
||||
|
||||
type CodeEditorTheme = {|
|
||||
name: string,
|
||||
@@ -37,6 +38,7 @@ const themes: Array<CodeEditorTheme> = [
|
||||
TomorrowNight,
|
||||
VibrantInk,
|
||||
NordDark,
|
||||
OneDark,
|
||||
];
|
||||
|
||||
export const getAllThemes = () => themes;
|
||||
|
@@ -50,38 +50,122 @@ export default class SelectionRectangle {
|
||||
this.viewPosition.getHeight()
|
||||
);
|
||||
|
||||
const startXPos =
|
||||
Math.floor(sceneStartPoint[0] / options.gridWidth) * options.gridWidth;
|
||||
const startYPos =
|
||||
Math.floor(sceneStartPoint[1] / options.gridHeight) * options.gridHeight;
|
||||
const offsetX =
|
||||
((options.gridOffsetX % options.gridWidth) + options.gridWidth) %
|
||||
options.gridWidth;
|
||||
const offsetY =
|
||||
((options.gridOffsetY % options.gridHeight) + options.gridHeight) %
|
||||
options.gridHeight;
|
||||
|
||||
const endXPos =
|
||||
Math.ceil(sceneEndPoint[0] / options.gridWidth) * options.gridWidth;
|
||||
const endYPos =
|
||||
Math.ceil(sceneEndPoint[1] / options.gridHeight) * options.gridHeight;
|
||||
const startX =
|
||||
Math.floor((sceneStartPoint[0] - offsetX) / options.gridWidth) *
|
||||
options.gridWidth +
|
||||
offsetX;
|
||||
const startY =
|
||||
Math.floor((sceneStartPoint[1] - offsetY) / options.gridHeight) *
|
||||
options.gridHeight +
|
||||
offsetY;
|
||||
|
||||
for (
|
||||
let Xpos = startXPos + options.gridOffsetX;
|
||||
Xpos < endXPos;
|
||||
Xpos += options.gridWidth
|
||||
) {
|
||||
const start = this.viewPosition.toCanvasCoordinates(Xpos, startYPos);
|
||||
const end = this.viewPosition.toCanvasCoordinates(Xpos, endYPos);
|
||||
const endX =
|
||||
Math.ceil((sceneEndPoint[0] - offsetX) / options.gridWidth) *
|
||||
options.gridWidth +
|
||||
offsetX;
|
||||
const endY =
|
||||
Math.ceil((sceneEndPoint[1] - offsetY) / options.gridHeight) *
|
||||
options.gridHeight +
|
||||
offsetY;
|
||||
|
||||
this.pixiGrid.moveTo(start[0], start[1]);
|
||||
this.pixiGrid.lineTo(end[0], end[1]);
|
||||
}
|
||||
if (options.gridType === 'isometric') {
|
||||
const countX = Math.round((endX - startX) / options.gridWidth);
|
||||
const countY = Math.round((endY - startY) / options.gridHeight);
|
||||
const lineCount = countX + countY;
|
||||
for (let i = 0; i < lineCount; ++i) {
|
||||
let lineStartX;
|
||||
let lineStartY;
|
||||
if (i < countX) {
|
||||
// top
|
||||
lineStartX = startX + options.gridWidth / 2 + i * options.gridWidth;
|
||||
lineStartY = startY;
|
||||
} else {
|
||||
// right
|
||||
lineStartX = endX;
|
||||
lineStartY =
|
||||
startY + options.gridHeight / 2 + (i - countX) * options.gridHeight;
|
||||
}
|
||||
let lineEndX;
|
||||
let lineEndY;
|
||||
if (i < countY) {
|
||||
// left
|
||||
lineEndX = startX;
|
||||
lineEndY = startY + options.gridHeight / 2 + i * options.gridHeight;
|
||||
} else {
|
||||
// bottom
|
||||
lineEndX =
|
||||
startX + options.gridWidth / 2 + (i - countY) * options.gridWidth;
|
||||
lineEndY = endY;
|
||||
}
|
||||
const start = this.viewPosition.toCanvasCoordinates(
|
||||
lineStartX,
|
||||
lineStartY
|
||||
);
|
||||
const end = this.viewPosition.toCanvasCoordinates(lineEndX, lineEndY);
|
||||
this.pixiGrid.moveTo(start[0], start[1]);
|
||||
this.pixiGrid.lineTo(end[0], end[1]);
|
||||
}
|
||||
for (let i = 0; i < lineCount; ++i) {
|
||||
let lineStartX;
|
||||
let lineStartY;
|
||||
if (i < countY) {
|
||||
// reverse left
|
||||
lineStartX = startX;
|
||||
lineStartY =
|
||||
startY +
|
||||
options.gridHeight / 2 +
|
||||
(countY - 1 - i) * options.gridHeight;
|
||||
} else {
|
||||
// top
|
||||
lineStartX =
|
||||
startX + options.gridWidth / 2 + (i - countY) * options.gridWidth;
|
||||
lineStartY = startY;
|
||||
}
|
||||
let lineEndX;
|
||||
let lineEndY;
|
||||
if (i < countX) {
|
||||
// bottom
|
||||
lineEndX = startX + options.gridWidth / 2 + i * options.gridWidth;
|
||||
lineEndY = endY;
|
||||
} else {
|
||||
// reverse right
|
||||
lineEndX = endX;
|
||||
lineEndY =
|
||||
startY +
|
||||
options.gridHeight / 2 +
|
||||
(lineCount - 1 - i) * options.gridHeight;
|
||||
}
|
||||
const start = this.viewPosition.toCanvasCoordinates(
|
||||
lineStartX,
|
||||
lineStartY
|
||||
);
|
||||
const end = this.viewPosition.toCanvasCoordinates(lineEndX, lineEndY);
|
||||
this.pixiGrid.moveTo(start[0], start[1]);
|
||||
this.pixiGrid.lineTo(end[0], end[1]);
|
||||
}
|
||||
} else {
|
||||
for (let x = startX; x < endX; x += options.gridWidth) {
|
||||
const start = this.viewPosition.toCanvasCoordinates(x, startY);
|
||||
const end = this.viewPosition.toCanvasCoordinates(x, endY);
|
||||
|
||||
for (
|
||||
let Ypos = startYPos + options.gridOffsetY;
|
||||
Ypos < endYPos;
|
||||
Ypos += options.gridHeight
|
||||
) {
|
||||
const start = this.viewPosition.toCanvasCoordinates(startXPos, Ypos);
|
||||
const end = this.viewPosition.toCanvasCoordinates(endXPos, Ypos);
|
||||
this.pixiGrid.moveTo(start[0], start[1]);
|
||||
this.pixiGrid.lineTo(end[0], end[1]);
|
||||
}
|
||||
|
||||
this.pixiGrid.moveTo(start[0], start[1]);
|
||||
this.pixiGrid.lineTo(end[0], end[1]);
|
||||
for (let y = startY; y < endY; y += options.gridHeight) {
|
||||
const start = this.viewPosition.toCanvasCoordinates(startX, y);
|
||||
const end = this.viewPosition.toCanvasCoordinates(endX, y);
|
||||
|
||||
this.pixiGrid.moveTo(start[0], start[1]);
|
||||
this.pixiGrid.lineTo(end[0], end[1]);
|
||||
}
|
||||
}
|
||||
|
||||
this.pixiGrid.endFill();
|
||||
|
@@ -14,15 +14,13 @@ const roundPositionsToGrid = (
|
||||
const newPos = pos;
|
||||
|
||||
if (options.grid && options.snap) {
|
||||
newPos[0] = roundPosition(
|
||||
newPos[0],
|
||||
roundPosition(
|
||||
newPos,
|
||||
options.gridWidth,
|
||||
options.gridOffsetX
|
||||
);
|
||||
newPos[1] = roundPosition(
|
||||
newPos[1],
|
||||
options.gridHeight,
|
||||
options.gridOffsetY
|
||||
options.gridOffsetX,
|
||||
options.gridOffsetY,
|
||||
options.gridType
|
||||
);
|
||||
} else {
|
||||
newPos[0] = Math.round(newPos[0]);
|
||||
|
@@ -7,24 +7,27 @@ export default class InstancesMover {
|
||||
this.instancePositions = {};
|
||||
this.totalDeltaX = 0;
|
||||
this.totalDeltaY = 0;
|
||||
this.temporaryPoint = [0, 0];
|
||||
}
|
||||
|
||||
setOptions(options) {
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
_roundXPosition(x, noGridSnap) {
|
||||
if (!this.options.snap || !this.options.grid || noGridSnap)
|
||||
return Math.round(x);
|
||||
|
||||
return roundPosition(x, this.options.gridWidth, this.options.gridOffsetX);
|
||||
}
|
||||
|
||||
_roundYPosition(y, noGridSnap) {
|
||||
if (!this.options.snap || !this.options.grid || noGridSnap)
|
||||
return Math.round(y);
|
||||
|
||||
return roundPosition(y, this.options.gridHeight, this.options.gridOffsetY);
|
||||
_roundPosition(pos, noGridSnap) {
|
||||
if (!this.options.snap || !this.options.grid || noGridSnap) {
|
||||
pos[0] = Math.round(pos[0]);
|
||||
pos[1] = Math.round(pos[1]);
|
||||
return;
|
||||
}
|
||||
roundPosition(
|
||||
pos,
|
||||
this.options.gridWidth,
|
||||
this.options.gridHeight,
|
||||
this.options.gridOffsetX,
|
||||
this.options.gridOffsetY,
|
||||
this.options.gridType
|
||||
);
|
||||
}
|
||||
|
||||
_getMoveDeltaX(followAxis) {
|
||||
@@ -55,19 +58,13 @@ export default class InstancesMover {
|
||||
y: selectedInstance.getY(),
|
||||
};
|
||||
}
|
||||
|
||||
selectedInstance.setX(
|
||||
this._roundXPosition(
|
||||
initialPosition.x + this._getMoveDeltaX(followAxis),
|
||||
noGridSnap
|
||||
)
|
||||
);
|
||||
selectedInstance.setY(
|
||||
this._roundYPosition(
|
||||
initialPosition.y + this._getMoveDeltaY(followAxis),
|
||||
noGridSnap
|
||||
)
|
||||
);
|
||||
this.temporaryPoint[0] =
|
||||
initialPosition.x + this._getMoveDeltaX(followAxis);
|
||||
this.temporaryPoint[1] =
|
||||
initialPosition.y + this._getMoveDeltaY(followAxis);
|
||||
this._roundPosition(this.temporaryPoint, noGridSnap);
|
||||
selectedInstance.setX(this.temporaryPoint[0]);
|
||||
selectedInstance.setY(this.temporaryPoint[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -48,8 +48,8 @@ export default class ViewPosition {
|
||||
toSceneCoordinates = (x: number, y: number): [number, number] => {
|
||||
x -= this._width / 2;
|
||||
y -= this._height / 2;
|
||||
x /= Math.abs(this._pixiContainer.scale.x);
|
||||
y /= Math.abs(this._pixiContainer.scale.y);
|
||||
x /= Math.abs(this.options.zoomFactor);
|
||||
y /= Math.abs(this.options.zoomFactor);
|
||||
|
||||
var viewRotation = 0;
|
||||
var tmp = x;
|
||||
@@ -80,8 +80,8 @@ export default class ViewPosition {
|
||||
Math.sin((viewRotation / 180) * Math.PI) * tmp +
|
||||
Math.cos((viewRotation / 180) * Math.PI) * y;
|
||||
|
||||
x *= Math.abs(this._pixiContainer.scale.x);
|
||||
y *= Math.abs(this._pixiContainer.scale.y);
|
||||
x *= Math.abs(this.options.zoomFactor);
|
||||
y *= Math.abs(this.options.zoomFactor);
|
||||
|
||||
return [x + this._width / 2, y + this._height / 2];
|
||||
};
|
||||
|
@@ -158,7 +158,7 @@ export default class InstancesEditor extends Component<Props> {
|
||||
|
||||
this.pixiRenderer.view.onwheel = event => {
|
||||
if (this.keyboardShortcuts.shouldZoom()) {
|
||||
this.zoomBy(-event.deltaY / 5000);
|
||||
this.zoomOnCursorBy(-event.deltaY / 5000);
|
||||
} else if (this.keyboardShortcuts.shouldScrollHorizontally()) {
|
||||
this.viewPosition.scrollBy(-event.deltaY / 10, 0);
|
||||
} else {
|
||||
@@ -457,6 +457,23 @@ export default class InstancesEditor extends Component<Props> {
|
||||
this.setZoomFactor(this.getZoomFactor() + value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Zoom and scroll so that the cursor stays on the same position scene-wise.
|
||||
*/
|
||||
zoomOnCursorBy(value: number) {
|
||||
const beforeZoomCursorPosition = this.getLastCursorSceneCoordinates();
|
||||
this.setZoomFactor(this.getZoomFactor() + value);
|
||||
const afterZoomCursorPosition = this.getLastCursorSceneCoordinates();
|
||||
// Compensate for the cursor change in position
|
||||
this.viewPosition.scrollBy(
|
||||
beforeZoomCursorPosition[0] - afterZoomCursorPosition[0],
|
||||
beforeZoomCursorPosition[1] - afterZoomCursorPosition[1]
|
||||
);
|
||||
if (this.props.onViewPositionChanged) {
|
||||
this.props.onViewPositionChanged(this.viewPosition);
|
||||
}
|
||||
}
|
||||
|
||||
getZoomFactor = () => {
|
||||
return this.props.options.zoomFactor;
|
||||
};
|
||||
|
@@ -2,6 +2,7 @@ import { Trans } from '@lingui/macro';
|
||||
import React, { Component } from 'react';
|
||||
import FlatButton from '../UI/FlatButton';
|
||||
import TextField from '../UI/TextField';
|
||||
import Checkbox from '../UI/Checkbox';
|
||||
import { ColumnStackLayout, ResponsiveLineStackLayout } from '../UI/Layout';
|
||||
import Dialog from '../UI/Dialog';
|
||||
import ColorField from '../UI/ColorField';
|
||||
@@ -21,6 +22,7 @@ export default class SetupGridDialog extends Component {
|
||||
gridOffsetX: this.state.gridOffsetX,
|
||||
gridOffsetY: this.state.gridOffsetY,
|
||||
gridColor: this.state.gridColor,
|
||||
gridType: this.state.gridType,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -69,7 +71,7 @@ export default class SetupGridDialog extends Component {
|
||||
type="number"
|
||||
value={this.state.gridWidth}
|
||||
onChange={(e, value) =>
|
||||
this.setState({ gridWidth: parseInt(value, 10) })
|
||||
this.setState({ gridWidth: parseFloat(value) })
|
||||
}
|
||||
/>
|
||||
<TextField
|
||||
@@ -78,7 +80,7 @@ export default class SetupGridDialog extends Component {
|
||||
type="number"
|
||||
value={this.state.gridHeight}
|
||||
onChange={(e, value) =>
|
||||
this.setState({ gridHeight: parseInt(value, 10) })
|
||||
this.setState({ gridHeight: parseFloat(value) })
|
||||
}
|
||||
/>
|
||||
</ResponsiveLineStackLayout>
|
||||
@@ -89,7 +91,7 @@ export default class SetupGridDialog extends Component {
|
||||
type="number"
|
||||
value={this.state.gridOffsetX}
|
||||
onChange={(e, value) =>
|
||||
this.setState({ gridOffsetX: parseInt(value, 10) })
|
||||
this.setState({ gridOffsetX: parseFloat(value) })
|
||||
}
|
||||
/>
|
||||
<TextField
|
||||
@@ -98,7 +100,18 @@ export default class SetupGridDialog extends Component {
|
||||
type="number"
|
||||
value={this.state.gridOffsetY}
|
||||
onChange={(e, value) =>
|
||||
this.setState({ gridOffsetY: parseInt(value, 10) })
|
||||
this.setState({ gridOffsetY: parseFloat(value) })
|
||||
}
|
||||
/>
|
||||
</ResponsiveLineStackLayout>
|
||||
<ResponsiveLineStackLayout noMargin expand>
|
||||
<Checkbox
|
||||
checked={this.state.gridType === 'isometric'}
|
||||
label={<Trans>Isometric</Trans>}
|
||||
onCheck={(e, check) =>
|
||||
this.setState({
|
||||
gridType: check ? 'isometric' : 'rectangular',
|
||||
})
|
||||
}
|
||||
/>
|
||||
</ResponsiveLineStackLayout>
|
||||
|
11
newIDE/app/src/UI/Theme/OneDarkTheme/index.js
Normal file
11
newIDE/app/src/UI/Theme/OneDarkTheme/index.js
Normal file
@@ -0,0 +1,11 @@
|
||||
import { createGdevelopTheme } from '../CreateTheme';
|
||||
|
||||
import styles from './OneDarkThemeVariables.json';
|
||||
import './OneDarkThemeVariables.css';
|
||||
|
||||
export default createGdevelopTheme(
|
||||
styles,
|
||||
'OneDarkTheme',
|
||||
'dark',
|
||||
'hue-rotate(-10deg) saturate(50%)'
|
||||
);
|
406
newIDE/app/src/UI/Theme/OneDarkTheme/theme.json
Normal file
406
newIDE/app/src/UI/Theme/OneDarkTheme/theme.json
Normal file
@@ -0,0 +1,406 @@
|
||||
{
|
||||
"theme": {
|
||||
"primary": {
|
||||
"color": {
|
||||
"value": "#61AFEF"
|
||||
},
|
||||
"text-contrast-color": {
|
||||
"value": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
"secondary": {
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
},
|
||||
"text-contrast-color": {
|
||||
"value": "#282C34"
|
||||
}
|
||||
},
|
||||
"surface": {
|
||||
"window": {
|
||||
"background-color": {
|
||||
"value": "#21252B"
|
||||
}
|
||||
},
|
||||
"canvas": {
|
||||
"background-color": {
|
||||
"value": "#282C34"
|
||||
}
|
||||
},
|
||||
"alternate-canvas": {
|
||||
"background-color": {
|
||||
"value": "#3E4452"
|
||||
}
|
||||
}
|
||||
},
|
||||
"selection": {
|
||||
"background-color": {
|
||||
"value": "#3E4452"
|
||||
},
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
},
|
||||
"text": {
|
||||
"default": {
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
},
|
||||
"secondary": {
|
||||
"color": {
|
||||
"value": "#ABB2BF"
|
||||
}
|
||||
},
|
||||
"disabled": {
|
||||
"color": {
|
||||
"value": "#9AA1AD"
|
||||
}
|
||||
},
|
||||
"contrast": {
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
}
|
||||
},
|
||||
"message": {
|
||||
"warning": {
|
||||
"color": {
|
||||
"value": "#E5C07B"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"color": {
|
||||
"value": "#E06C75"
|
||||
}
|
||||
},
|
||||
"valid": {
|
||||
"color": {
|
||||
"value": "#98C379"
|
||||
}
|
||||
},
|
||||
"empty-shadow": {
|
||||
"color": {
|
||||
"value": "transparent"
|
||||
}
|
||||
}
|
||||
},
|
||||
"toolbar-separator": {
|
||||
"color": {
|
||||
"value": "#3E4452"
|
||||
}
|
||||
},
|
||||
"closable-tabs": {
|
||||
"default": {
|
||||
"background-color": {
|
||||
"value": "#21252B"
|
||||
},
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
},
|
||||
"selected": {
|
||||
"background-color": {
|
||||
"value": "#4C5361"
|
||||
},
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
}
|
||||
},
|
||||
"list-item": {
|
||||
"group": {
|
||||
"text": {
|
||||
"color": {
|
||||
"value": "#ABB2BF"
|
||||
}
|
||||
},
|
||||
"text-deprecated": {
|
||||
"color": {
|
||||
"value": "#9AA1AD"
|
||||
}
|
||||
}
|
||||
},
|
||||
"separator": {
|
||||
"color": {
|
||||
"value": "#3E4452"
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"color": {
|
||||
"value": "#E5C07B"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"color": {
|
||||
"value": "#E06C75"
|
||||
}
|
||||
}
|
||||
},
|
||||
"right-icon": {
|
||||
"color": {
|
||||
"value": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
"palette": {
|
||||
"black": {
|
||||
"value": "#6E2A2A"
|
||||
},
|
||||
"white": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
}
|
||||
},
|
||||
"input": {
|
||||
"border-bottom": {
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
}
|
||||
},
|
||||
"tabs": {
|
||||
"background-color": {
|
||||
"value": "#4C5361"
|
||||
}
|
||||
},
|
||||
"event-sheet": {
|
||||
"event-tree": {
|
||||
"background-color": {
|
||||
"value": "#282C34"
|
||||
}
|
||||
},
|
||||
"rst": {
|
||||
"move-handle": {
|
||||
"background-color": {
|
||||
"value": "#3E4452"
|
||||
}
|
||||
},
|
||||
"move-handle-hover": {
|
||||
"background-color": {
|
||||
"value": "#6C7D96"
|
||||
}
|
||||
},
|
||||
"line": {
|
||||
"background-color": {
|
||||
"value": "#ABB2BF"
|
||||
}
|
||||
},
|
||||
"row-contents": {
|
||||
"background-color": {
|
||||
"value": "#282C34"
|
||||
},
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
},
|
||||
"row-search": {
|
||||
"border-color": {
|
||||
"value": "#18DCF2"
|
||||
},
|
||||
"border-left-width-match": {
|
||||
"value": "3px"
|
||||
},
|
||||
"border-left-width-focus": {
|
||||
"value": "5px"
|
||||
}
|
||||
}
|
||||
},
|
||||
"rst-with-results": {
|
||||
"background-color": {
|
||||
"value": "#D3D3D3"
|
||||
},
|
||||
"border": {
|
||||
"value": "1px #D3D3D3 solid"
|
||||
}
|
||||
},
|
||||
"selectable": {
|
||||
"background-color": {
|
||||
"value": "rgba(0, 0, 0, 0.1)"
|
||||
},
|
||||
"border": {
|
||||
"value": "1px #282C34 solid"
|
||||
},
|
||||
"selected-border": {
|
||||
"value": "1px #4AB0E4 dashed"
|
||||
}
|
||||
},
|
||||
"conditions": {
|
||||
"background-color": {
|
||||
"value": "#3E4452"
|
||||
},
|
||||
"border-color": {
|
||||
"value": "#3E4452"
|
||||
},
|
||||
"border": {
|
||||
"value": "1px #3E4452 solid"
|
||||
},
|
||||
"color": {
|
||||
"value": "rgb(209, 209, 209)"
|
||||
},
|
||||
"border-right-color": {
|
||||
"value": "#494949"
|
||||
},
|
||||
"border-bottom-color": {
|
||||
"value": "black"
|
||||
}
|
||||
},
|
||||
"actions": {
|
||||
"background-color": {
|
||||
"value": "#282C34"
|
||||
},
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
},
|
||||
"sub-instructions": {
|
||||
"border-color": {
|
||||
"value": "#282C34"
|
||||
},
|
||||
"border": {
|
||||
"value": "1px #282C34 solid"
|
||||
}
|
||||
},
|
||||
"instruction-parameter": {
|
||||
"base": {
|
||||
"color": {
|
||||
"value": "#98C379"
|
||||
}
|
||||
},
|
||||
"expression": {
|
||||
"color": {
|
||||
"value": "#E5C07B"
|
||||
}
|
||||
},
|
||||
"object": {
|
||||
"color": {
|
||||
"value": "#C678DD"
|
||||
}
|
||||
},
|
||||
"behavior": {
|
||||
"color": {
|
||||
"value": "#E09563"
|
||||
}
|
||||
},
|
||||
"operator": {
|
||||
"color": {
|
||||
"value": "#B77CFF"
|
||||
}
|
||||
},
|
||||
"var": {
|
||||
"color": {
|
||||
"value": "#56B6C2"
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"color": {
|
||||
"value": "#E06C75"
|
||||
},
|
||||
"background-color": {
|
||||
"value": "#E06C7544"
|
||||
}
|
||||
}
|
||||
},
|
||||
"drop-indicator": {
|
||||
"can-drop": {
|
||||
"border-top-color": {
|
||||
"value": "#61AFEF"
|
||||
}
|
||||
},
|
||||
"cannot-drop": {
|
||||
"border-top-color": {
|
||||
"value": "#E06C75"
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"container": {
|
||||
"background-color": {
|
||||
"value": "#3E4452"
|
||||
},
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
},
|
||||
"selectable-link": {
|
||||
"color": {
|
||||
"value": "#C678DD"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"markdown": {
|
||||
"blockquote": {
|
||||
"border-left": {
|
||||
"color": {
|
||||
"value": "rgba(221, 221, 221, 0.6)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"color": {
|
||||
"value": "rgb(221, 221, 221)"
|
||||
}
|
||||
}
|
||||
},
|
||||
"mosaic": {
|
||||
"title": {
|
||||
"color": {
|
||||
"value": "#FFFFFF"
|
||||
}
|
||||
},
|
||||
"layout": {
|
||||
"border-color": {
|
||||
"value": "#3E4452"
|
||||
},
|
||||
"background-color": {
|
||||
"value": "#21252B"
|
||||
}
|
||||
},
|
||||
"toolbar": {
|
||||
"background-color": {
|
||||
"value": "#4C5361"
|
||||
},
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
},
|
||||
"border-color-hover": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
"border": {
|
||||
"color": {
|
||||
"value": "#282C34"
|
||||
}
|
||||
},
|
||||
"text": {
|
||||
"color": {
|
||||
"value": "#ABB2BF"
|
||||
},
|
||||
"color-header": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
},
|
||||
"row": {
|
||||
"odd": {
|
||||
"background-color": {
|
||||
"value": "#282C34"
|
||||
}
|
||||
},
|
||||
"even": {
|
||||
"background-color": {
|
||||
"value": "#21252B"
|
||||
}
|
||||
},
|
||||
"selected": {
|
||||
"background-color": {
|
||||
"value": "#3E4452"
|
||||
},
|
||||
"color": {
|
||||
"value": "#D6DEEC"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,6 +3,7 @@ import DefaultTheme from './DefaultTheme';
|
||||
import DarkTheme from './DarkTheme';
|
||||
import NordTheme from './NordTheme';
|
||||
import SolarizedDarkTheme from './SolarizedDarkTheme';
|
||||
import OneDarkTheme from './OneDarkTheme';
|
||||
|
||||
/*eslint no-useless-computed-key: "off"*/
|
||||
export const themes = {
|
||||
@@ -10,4 +11,5 @@ export const themes = {
|
||||
['Dark']: DarkTheme,
|
||||
['Nord']: NordTheme,
|
||||
['Solarized Dark']: SolarizedDarkTheme,
|
||||
['One Dark']: OneDarkTheme,
|
||||
};
|
||||
|
@@ -1,12 +1,69 @@
|
||||
// @flow
|
||||
|
||||
export const roundPosition = (
|
||||
pos: number,
|
||||
gridSize: number,
|
||||
gridOffset: number
|
||||
pos: [number, number],
|
||||
gridWidth: number,
|
||||
gridHeight: number,
|
||||
gridOffsetX: number,
|
||||
gridOffsetY: number,
|
||||
gridType: string
|
||||
) => {
|
||||
if (gridSize <= 0) {
|
||||
return Math.round(pos);
|
||||
if (gridType === 'isometric') {
|
||||
if (gridWidth <= 0 || gridHeight <= 0) {
|
||||
pos[0] = Math.round(pos[0]);
|
||||
pos[1] = Math.round(pos[1]);
|
||||
return;
|
||||
}
|
||||
// Why do we need this?
|
||||
// Take a 2x2 squares, put a diamond inside each square,
|
||||
// there is a 5th diamond in the center
|
||||
// So, half cells are needed, but some are not to be used.
|
||||
// It makes a pattern in diagonal like this:
|
||||
// o-o-o-
|
||||
// -o-o-o
|
||||
// o-o-o-
|
||||
let cellX = Math.round(((pos[0] - gridOffsetX) * 2) / gridWidth);
|
||||
let cellY = Math.round(((pos[1] - gridOffsetY) * 2) / gridHeight);
|
||||
|
||||
if ((((cellX + cellY) % 2) + 2) % 2 === 1) {
|
||||
// This cell should not be used, find the nearest one
|
||||
const deltaX =
|
||||
(pos[0] - ((cellX / 2) * gridWidth + gridOffsetX)) / gridWidth;
|
||||
const deltaY =
|
||||
(pos[1] - ((cellY / 2) * gridHeight + gridOffsetY)) / gridHeight;
|
||||
|
||||
if (Math.abs(deltaX) > Math.abs(deltaY)) {
|
||||
if (deltaX > 0) {
|
||||
cellX++;
|
||||
} else {
|
||||
cellX--;
|
||||
}
|
||||
} else {
|
||||
if (deltaY > 0) {
|
||||
cellY++;
|
||||
} else {
|
||||
cellY--;
|
||||
}
|
||||
}
|
||||
}
|
||||
// magnet to the half cell
|
||||
pos[0] = (cellX / 2) * gridWidth + gridOffsetX;
|
||||
pos[1] = (cellY / 2) * gridHeight + gridOffsetY;
|
||||
} else {
|
||||
if (gridWidth <= 0) {
|
||||
pos[0] = Math.round(pos[0]);
|
||||
} else {
|
||||
pos[0] =
|
||||
Math.floor((pos[0] - gridOffsetX) / gridWidth) * gridWidth +
|
||||
gridOffsetX;
|
||||
}
|
||||
|
||||
if (gridHeight <= 0) {
|
||||
pos[1] = Math.round(pos[1]);
|
||||
} else {
|
||||
pos[1] =
|
||||
Math.floor((pos[1] - gridOffsetY) / gridHeight) * gridHeight +
|
||||
gridOffsetY;
|
||||
}
|
||||
}
|
||||
return Math.floor((pos - gridOffset) / gridSize) * gridSize + gridOffset;
|
||||
};
|
||||
|
@@ -2,7 +2,7 @@
|
||||
"name": "gdevelop",
|
||||
"productName": "GDevelop 5",
|
||||
"description": "GDevelop 5 IDE - the open-source, cross-platform game engine designed for everyone",
|
||||
"version": "5.0.0-beta106",
|
||||
"version": "5.0.0-beta107",
|
||||
"author": "Florian Rival",
|
||||
"license": "MIT",
|
||||
"homepage": "http://gdevelop-app.com",
|
||||
|
Reference in New Issue
Block a user