Compare commits

...

4 Commits

Author SHA1 Message Date
Florian Rival
bdbf7fd9fc Add support for editing BehaviorSharedData in newIDE
TODO:
* Support for cancelling modifications made on it in ScenePropertiesDialog
2018-01-27 19:13:27 +01:00
Florian Rival
6bbedbd8f9 Fix BehaviorSharedData not created by newIDE + fix warnings 2018-01-27 17:00:44 +01:00
Florian Rival
648bd1ff2e Show warning if game name or package name is empty when exporting in newIDE 2018-01-24 23:31:02 +01:00
Florian Rival
d4288caedb Fix .env file loading with electron-app and bump newIDE version 2018-01-23 00:15:13 +01:00
28 changed files with 346 additions and 51 deletions

View File

@@ -70,7 +70,8 @@
"ratio": "cpp",
"atomic": "cpp",
"locale": "cpp",
"string_view": "cpp"
"string_view": "cpp",
"__string": "cpp"
},
"files.exclude": {
"Binaries/*build*": true,

View File

@@ -68,7 +68,7 @@ public:
* Usage example:
\code
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[ToString(_("Initial speed"))].SetValue("5");
properties[_("Initial speed")].SetValue(gd::String::From(initialSpeed));
return properties;
\endcode

View File

@@ -5,6 +5,10 @@
*/
#include "GDCore/Project/BehaviorsSharedData.h"
#if defined(GD_IDE_ONLY)
#include <map>
#include "GDCore/IDE/Dialogs/PropertyDescriptor.h"
#endif
namespace gd
{
@@ -13,4 +17,12 @@ BehaviorsSharedData::~BehaviorsSharedData()
{
};
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::PropertyDescriptor> BehaviorsSharedData::GetProperties(gd::Project & project) const
{
std::map<gd::String, gd::PropertyDescriptor> nothing;
return nothing;
}
#endif
}

View File

@@ -8,9 +8,13 @@
#define BEHAVIORSSHAREDDATA_H
#include <memory>
#include <map>
#include "GDCore/String.h"
class BehaviorsRuntimeSharedData;
namespace gd { class SerializerElement; }
namespace gd { class PropertyDescriptor; }
namespace gd { class Project; }
namespace gd { class Layout; }
namespace gd
{
@@ -52,6 +56,31 @@ public:
virtual void SetTypeName(const gd::String & type_) { type = type_; };
#if defined(GD_IDE_ONLY)
/**
* \brief Called when the IDE wants to know about the properties of the shared data.
*
* Usage example:
\code
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Initial speed")].SetValue(gd::String::From(initialSpeed));
return properties;
\endcode
*
* \return a std::map with properties names as key.
* \see gd::PropertyDescriptor
*/
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(gd::Project & project) const;
/**
* \brief Called when the IDE wants to update a property of the shared data
*
* \return false if the new value cannot be set
* \see gd::InitialInstance
*/
virtual bool UpdateProperty(const gd::String & name, const gd::String & value, gd::Project & project) {return false;};
/**
* \brief Serialize behaviors shared data.
*/

View File

@@ -29,6 +29,7 @@ namespace gd
{
gd::Layer Layout::badLayer;
gd::BehaviorsSharedData Layout::badBehaviorSharedData;
Layout::Layout(const Layout & other)
{
@@ -74,6 +75,53 @@ void Layout::SetName(const gd::String & name_)
mangledName = gd::SceneNameMangler::GetMangledSceneName(name);
};
bool Layout::HasBehaviorSharedData(const gd::String & behaviorName)
{
return behaviorsInitialSharedDatas.find(behaviorName) != behaviorsInitialSharedDatas.end();
}
std::vector <gd::String> Layout::GetAllBehaviorSharedDataNames() const
{
std::vector < gd::String > allNames;
for (auto & it : behaviorsInitialSharedDatas)
allNames.push_back(it.first);
return allNames;
}
const gd::BehaviorsSharedData & Layout::GetBehaviorSharedData(const gd::String & behaviorName) const
{
auto it = behaviorsInitialSharedDatas.find(behaviorName);
if (it != behaviorsInitialSharedDatas.end())
return *it->second;
return badBehaviorSharedData;
}
gd::BehaviorsSharedData & Layout::GetBehaviorSharedData(const gd::String & behaviorName)
{
auto it = behaviorsInitialSharedDatas.find(behaviorName);
if (it != behaviorsInitialSharedDatas.end())
return *it->second;
return badBehaviorSharedData;
}
std::shared_ptr<gd::BehaviorsSharedData> Layout::GetBehaviorSharedDataSmartPtr(const gd::String & behaviorName)
{
auto it = behaviorsInitialSharedDatas.find(behaviorName);
if (it != behaviorsInitialSharedDatas.end())
return it->second;
return std::shared_ptr<gd::BehaviorsSharedData>();
}
const std::map < gd::String, std::shared_ptr<gd::BehaviorsSharedData> > & Layout::GetAllBehaviorSharedData() const
{
return behaviorsInitialSharedDatas;
}
gd::Layer & Layout::GetLayer(const gd::String & name)
{
std::vector<gd::Layer>::iterator layer = find_if(initialLayers.begin(), initialLayers.end(), bind2nd(gd::LayerHasName(), name));

View File

@@ -253,15 +253,45 @@ public:
///@}
/**
* Make sure that the scene had an instance of shared data for
* This ensures that the scene had an instance of shared data for
* every behavior of every object that can be used on the scene
* ( i.e. the objects of the scene and the global objects )
* (i.e. the objects of the scene and the global objects)
*
* Must be called when a behavior have been added/deleted
* or when a scene have been added to a project.
*/
void UpdateBehaviorsSharedData(gd::Project & project);
/**
* \brief Get the names of all shared data stored for behaviors
*/
std::vector <gd::String> GetAllBehaviorSharedDataNames() const;
/**
* \brief Check if shared data are stored for a behavior
*/
bool HasBehaviorSharedData(const gd::String & behaviorName);
/**
* \brief Get the shared data stored for a behavior
*/
const gd::BehaviorsSharedData & GetBehaviorSharedData(const gd::String & behaviorName) const;
/**
* \brief Get the shared data stored for a behavior
*/
gd::BehaviorsSharedData & GetBehaviorSharedData(const gd::String & behaviorName);
/**
* \brief Get a map of all shared data stored for behaviors
*/
const std::map < gd::String, std::shared_ptr<gd::BehaviorsSharedData> > & GetAllBehaviorSharedData() const;
/**
* \brief Get the (smart pointer to the) shared data stored for a behavior.
*/
std::shared_ptr<gd::BehaviorsSharedData> GetBehaviorSharedDataSmartPtr(const gd::String & behaviorName);
#if defined(GD_IDE_ONLY)
/**
* Return the settings associated to the layout.
@@ -357,9 +387,6 @@ public:
void UnserializeFrom(gd::Project & project, const SerializerElement & element);
///@}
//TODO: Send this to private part.
std::map < gd::String, std::shared_ptr<gd::BehaviorsSharedData> > behaviorsInitialSharedDatas; ///< Initial shared datas of behaviors
//TODO: GD C++ Platform specific code below
#if defined(GD_IDE_ONLY)
/** \name Events compilation and bitcode management
@@ -442,6 +469,7 @@ private:
gd::InitialInstancesContainer initialInstances; ///< Initial instances
std::vector < gd::Layer > initialLayers; ///< Initial layers
ObjectGroupsContainer objectGroups; ///< Objects groups
std::map < gd::String, std::shared_ptr<gd::BehaviorsSharedData> > behaviorsInitialSharedDatas; ///< 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.
float oglFOV; ///< OpenGL Field Of View value
@@ -449,6 +477,7 @@ private:
float oglZFar; ///< OpenGL Far Z position
bool disableInputWhenNotFocused; /// If set to true, the input must be disabled when the window do not have the focus.
static gd::Layer badLayer; ///< Null object, returned when GetLayer can not find an appropriate layer.
static gd::BehaviorsSharedData badBehaviorSharedData; ///< Null object, returned when GetBehaviorSharedData can not find the specified behavior shared data.
#if defined(GD_IDE_ONLY)
EventsList events; ///< Scene events
gd::LayoutEditorCanvasOptions associatedSettings;

View File

@@ -21,7 +21,7 @@ class GD_EXTENSION_API AdMobObject : public gd::Object
public:
AdMobObject(gd::String name_);
virtual ~AdMobObject() {};
virtual std::unique_ptr<gd::Object> Clone() const { return gd::make_unique<AdMobObject>(*this); }
virtual std::unique_ptr<gd::Object> Clone() const override { return gd::make_unique<AdMobObject>(*this); }
#if !defined(GD_NO_WX_GUI)
void DrawInitialInstance(gd::InitialInstance & instance, sf::RenderTarget & renderTarget, gd::Project & project, gd::Layout & layout) override;

View File

@@ -322,13 +322,13 @@ PathBehaviorEditor::PathBehaviorEditor(wxWindow* parent, gd::Project & game_, gd
followAngleCheck->SetValue(behavior.FollowAngle());
//Setup shared datas
if ( !scene || scene->behaviorsInitialSharedDatas.find(behavior.GetName()) == scene->behaviorsInitialSharedDatas.end())
if (!scene || !scene->HasBehaviorSharedData(behavior.GetName()))
{
gd::LogError(_("Unable to access to shared datas."));
return;
}
sharedDatas = std::dynamic_pointer_cast<ScenePathDatas>(scene->behaviorsInitialSharedDatas[behavior.GetName()]);
sharedDatas = std::dynamic_pointer_cast<ScenePathDatas>(scene->GetBehaviorSharedDataSmartPtr(behavior.GetName()));
if ( sharedDatas == std::shared_ptr<ScenePathDatas>() )
{

View File

@@ -241,13 +241,13 @@ scene(scene_)
}
//Setup shared datas
if ( !scene || scene->behaviorsInitialSharedDatas.find(behavior.GetName()) == scene->behaviorsInitialSharedDatas.end())
if (!scene || !scene->HasBehaviorSharedData(behavior.GetName()))
{
gd::LogError(_("Unable to access to shared datas."));
return;
}
sharedDatas = std::dynamic_pointer_cast<ScenePhysicsDatas>(scene->behaviorsInitialSharedDatas[behavior.GetName()]);
sharedDatas = std::dynamic_pointer_cast<ScenePhysicsDatas>(scene->GetBehaviorSharedDataSmartPtr(behavior.GetName()));
if ( sharedDatas == std::shared_ptr<ScenePhysicsDatas>() )
{

View File

@@ -6,9 +6,46 @@ This project is released under the MIT License.
*/
#include "ScenePhysicsDatas.h"
#include "GDCore/Tools/Localization.h"
#include "GDCore/Serialization/SerializerElement.h"
#if defined(GD_IDE_ONLY)
#include <map>
#include "GDCore/String.h"
#include "GDCore/CommonTools.h"
#include "GDCore/Project/Project.h"
#include "GDCore/IDE/Dialogs/PropertyDescriptor.h"
#endif
#if defined(GD_IDE_ONLY)
std::map<gd::String, gd::PropertyDescriptor> ScenePhysicsDatas::GetProperties(gd::Project & project) const
{
std::map<gd::String, gd::PropertyDescriptor> properties;
properties[_("Gravity on X axis (in m/s²)")].SetValue(gd::String::From(gravityX));
properties[_("Gravity on Y axis (in m/s²)")].SetValue(gd::String::From(gravityY));
properties[_("X Scale: number of pixels for 1 meter")].SetValue(gd::String::From(scaleX));
properties[_("Y Scale: number of pixels for 1 meter")].SetValue(gd::String::From(scaleY));
return properties;
}
bool ScenePhysicsDatas::UpdateProperty(const gd::String & name, const gd::String & value, gd::Project & project)
{
if (name == _("Gravity on X axis (in m/s²)")) {
gravityX = value.To<float>();
}
if (name == _("Gravity on Y axis (in m/s²)")) {
gravityY = value.To<float>();
}
if (name == _("X scale: number of pixels for 1 meter")) {
scaleX = value.To<float>();
}
if (name == _("Y scale: number of pixels for 1 meter")) {
scaleY = value.To<float>();
}
return true;
}
void ScenePhysicsDatas::SerializeTo(gd::SerializerElement & element) const
{
element.SetAttribute("gravityX", gravityX);

View File

@@ -34,6 +34,8 @@ public:
}
#if defined(GD_IDE_ONLY)
virtual std::map<gd::String, gd::PropertyDescriptor> GetProperties(gd::Project & project) const;
virtual bool UpdateProperty(const gd::String & name, const gd::String & value, gd::Project & project);
virtual void SerializeTo(gd::SerializerElement & element) const;
#endif

View File

@@ -450,7 +450,7 @@ bool RuntimeScene::LoadFromSceneAndCustomInstances( const gd::Layout & scene, co
//Behaviors shared data
std::cout << ".";
behaviorsSharedDatas.LoadFrom(scene.behaviorsInitialSharedDatas);
behaviorsSharedDatas.LoadFrom(scene.GetAllBehaviorSharedData());
std::cout << ".";
//Extensions specific initialization

View File

@@ -9,6 +9,9 @@ import { findGDJS } from './LocalGDJSFinder';
import localFileSystem from './LocalFileSystem';
import LocalFolderPicker from '../../UI/LocalFolderPicker';
import HelpButton from '../../UI/HelpButton';
import { displaySanityCheck } from '../SanityChecker';
import { getSanityMessages } from '../SanityChecker/CordovaSanityChecker';
import { translate } from 'react-i18next';
import assignIn from 'lodash/assignIn';
import optionalRequire from '../../Utils/OptionalRequire';
import Window from '../../Utils/Window';
@@ -17,7 +20,7 @@ const shell = electron ? electron.shell : null;
const gd = global.gd;
export default class LocalCordovaExport extends Component {
class LocalCordovaExport extends Component {
state = {
exportFinishedDialogOpen: false,
outputDir: '',
@@ -53,11 +56,13 @@ export default class LocalCordovaExport extends Component {
};
launchExport = () => {
const { project } = this.props;
const { t, project } = this.props;
if (!project) return;
sendExportLaunched('local-cordova');
if (!displaySanityCheck(t, getSanityMessages(t, project))) return;
const outputDir = this.state.outputDir;
project.setLastCompilationDirectory(outputDir);
@@ -89,7 +94,7 @@ export default class LocalCordovaExport extends Component {
};
render() {
const { project } = this.props;
const { t, project } = this.props;
if (!project) return null;
return (
@@ -125,7 +130,7 @@ export default class LocalCordovaExport extends Component {
/>
</Line>
<Dialog
title="Export finished"
title={t('Export finished')}
actions={[
<FlatButton
key="open"
@@ -162,10 +167,12 @@ export default class LocalCordovaExport extends Component {
fullWidth
primary
onClick={() => this.openPhoneGapBuild()}
label="Open PhoneGap Build"
label={t('Open PhoneGap Build')}
/>
</Dialog>
</Column>
);
}
}
export default translate()(LocalCordovaExport);

View File

@@ -25,6 +25,9 @@ import Window from '../../../Utils/Window';
import { delay } from '../../../Utils/Delay';
import CreateProfile from '../../../Profile/CreateProfile';
import LimitDisplayer from '../../../Profile/LimitDisplayer';
import { displaySanityCheck } from '../../SanityChecker';
import { getSanityMessages } from '../../SanityChecker/CordovaSanityChecker';
import { translate, type TranslatorProps } from 'react-i18next';
const path = optionalRequire('path');
const os = optionalRequire('os');
const electron = optionalRequire('electron');
@@ -51,7 +54,7 @@ type State = {
errored: boolean,
};
type Props = WithUserProfileProps & {
type Props = WithUserProfileProps & TranslatorProps & {
project: gdProject,
onChangeSubscription: Function,
};
@@ -97,7 +100,7 @@ class LocalOnlineCordovaExport extends Component<Props, State> {
};
launchExport = (): Promise<string> => {
const { project } = this.props;
const { project, t } = this.props;
if (!project) return Promise.reject();
return LocalOnlineCordovaExport.prepareExporter()
@@ -114,7 +117,7 @@ class LocalOnlineCordovaExport extends Component<Props, State> {
return outputDir;
})
.catch(err => {
showErrorBox('Unable to export the game', err);
showErrorBox(t('Unable to export the game'), err);
throw err;
});
};
@@ -198,8 +201,12 @@ class LocalOnlineCordovaExport extends Component<Props, State> {
};
launchWholeExport = () => {
const { t, project } = this.props;
sendExportLaunched('local-online-cordova');
if (!displaySanityCheck(t, getSanityMessages(t, project)))
return;
const handleError = (message: string) => err => {
if (!this.state.errored) {
this.setState({
@@ -226,33 +233,33 @@ class LocalOnlineCordovaExport extends Component<Props, State> {
exportStep: 'compress',
});
return this.launchCompression(outputDir);
}, handleError('Error while exporting the game.'))
}, handleError(t('Error while exporting the game.')))
.then(outputFile => {
this.setState({
exportStep: 'upload',
});
return this.launchUpload(outputFile);
}, handleError('Error while compressing the game.'))
}, handleError(t('Error while compressing the game.')))
.then((uploadBucketKey: string) => {
this.setState({
exportStep: 'waiting-for-build',
});
return this.launchBuild(uploadBucketKey);
}, handleError('Error while uploading the game. Check your internet connection or try again later.'))
}, handleError(t('Error while uploading the game. Check your internet connection or try again later.')))
.then(buildId => {
this.setState({
exportStep: 'build',
});
return this.pollBuild(buildId);
}, handleError('Error while lauching the build of the game.'))
}, handleError(t('Error while lauching the build of the game.')))
.then(build => {
this.setState({
exportStep: 'done',
build,
});
this.props.onRefreshUserProfile();
}, handleError('Error while building the game.'));
}, handleError(t('Error while building the game.')));
};
_download = () => {
@@ -291,6 +298,7 @@ class LocalOnlineCordovaExport extends Component<Props, State> {
onLogin,
subscription,
limits,
t,
} = this.props;
if (!project) return null;
@@ -302,13 +310,12 @@ class LocalOnlineCordovaExport extends Component<Props, State> {
return (
<Column noMargin>
<Line>
Packaging your game for Android will create an APK file that can be
installed on Android phones, based on Cordova framework.
{t("Packaging your game for Android will create an APK file that can be installed on Android phones, based on Cordova framework.")}
</Line>
{authenticated && (
<Line justifyContent="center">
<RaisedButton
label="Package for Android"
label={t("Package for Android")}
primary
onClick={this.launchWholeExport}
disabled={disableBuild}
@@ -324,7 +331,7 @@ class LocalOnlineCordovaExport extends Component<Props, State> {
)}
{!authenticated && (
<CreateProfile
message="Create an account to build your game for Android in one-click:"
message={t("Create an account to build your game for Android in one-click:")}
onLogin={onLogin}
/>
)}
@@ -347,6 +354,6 @@ class LocalOnlineCordovaExport extends Component<Props, State> {
}
}
export default withUserProfile({ fetchLimits: true, fetchSubscription: true })(
export default translate()(withUserProfile({ fetchLimits: true, fetchSubscription: true })(
LocalOnlineCordovaExport
);
));

View File

@@ -0,0 +1,30 @@
// @flow
import { type TFunction } from 'react-i18next';
import { type SanityMessages } from './index';
export const getSanityMessages = (t: TFunction, project: gdProject): SanityMessages => {
let errors = [];
let warnings = [];
if (!project.getPackageName()) {
errors.push(
t(
'The package name is empty. Choose and enter a package name in the game properties.'
)
);
} else if (project.getPackageName().length >= 255) {
errors.push(t('The package name is too long.'));
}
if (!project.getName()) {
errors.push(
t(
'The game name is empty. Choose and enter a name in the game properties.'
)
);
}
return {
errors,
warnings,
};
};

View File

@@ -0,0 +1,25 @@
// @flow
import { type TFunction } from 'react-i18next';
import { showErrorBox } from '../../UI/Messages/MessageBox';
export type SanityMessages = {
errors: Array<string>,
warnings: Array<string>,
};
export const displaySanityCheck = (
t: TFunction,
messages: SanityMessages
): boolean => {
if (messages.errors.length) {
showErrorBox(
t(
'Your game has some invalid elements, please fix these before continuing:'
) +
'\n\n' +
messages.errors.map(message => `- ${message}`).join('\n')
);
}
return !messages.errors.length;
};

View File

@@ -241,7 +241,11 @@ export default class MainFrame extends Component<*, State> {
const name = newNameGenerator('NewScene', name =>
currentProject.hasLayoutNamed(name)
);
currentProject.insertNewLayout(name, currentProject.getLayoutsCount());
const newLayout = currentProject.insertNewLayout(
name,
currentProject.getLayoutsCount()
);
newLayout.updateBehaviorsSharedData(currentProject);
this.forceUpdate();
};
@@ -908,7 +912,7 @@ export default class MainFrame extends Component<*, State> {
open={profileDialogOpen}
authentification={authentification}
onClose={() => this.openProfile(false)}
onChangeSubscription={(onDone) => this.openSubscription(true, onDone)}
onChangeSubscription={onDone => this.openSubscription(true, onDone)}
/>
<SubscriptionDialog
onClose={() => {

View File

@@ -257,7 +257,7 @@ export default class ObjectsListContainer extends React.Component<
const { object: pasteObject, global } = objectWithContext;
const { object: copiedObject, type, name } = Clipboard.get(CLIPBOARD_KIND);
const { project, objectsContainer } = this.props;
const { project, objectsContainer, onObjectPasted } = this.props;
const newName = newNameGenerator(
'CopyOf' + name,
@@ -287,6 +287,7 @@ export default class ObjectsListContainer extends React.Component<
);
this.forceUpdate();
if (onObjectPasted) onObjectPasted(newObject);
};
_editName = (objectWithContext: ?ObjectWithContext) => {

View File

@@ -202,6 +202,7 @@ export default class ProjectManager extends React.Component {
project
);
newLayout.setName(newName);
newLayout.updateBehaviorsSharedData(project);
this.forceUpdate();
};

View File

@@ -1,9 +1,14 @@
import React, { Component } from 'react';
import FlatButton from 'material-ui/FlatButton';
import TextField from 'material-ui/TextField';
import Dialog from '../../UI/Dialog';
import RaisedButton from 'material-ui/RaisedButton';
import Dialog from '../../UI/Dialog';
import ColorField from '../../UI/ColorField';
import EmptyMessage from '../../UI/EmptyMessage';
import PropertiesEditor from '../../PropertiesEditor';
import propertiesMapToSchema from '../../PropertiesEditor/PropertiesMapToSchema';
import some from 'lodash/some';
const gd = global.gd;
export default class ScenePropertiesDialog extends Component {
constructor(props) {
@@ -43,20 +48,49 @@ export default class ScenePropertiesDialog extends Component {
};
render() {
const { layout, project } = this.props;
const actions = [
// TODO: Add support for cancelling modifications made to BehaviorSharedData
// (either by enhancing a function like propertiesMapToSchema or using copies)
// and then re-enable cancel button.
// <FlatButton
// label="Cancel"
// primary={false}
// onClick={this.props.onClose}
// />,
<FlatButton
label="Cancel"
primary={false}
onClick={this.props.onClose}
/>,
<FlatButton
label="Apply"
label="Ok"
primary={true}
keyboardFocused={true}
onClick={this._onApply}
/>,
];
const allBehaviorSharedDataNames = layout
.getAllBehaviorSharedDataNames()
.toJSArray();
const propertiesEditors = allBehaviorSharedDataNames.map(name => {
const sharedData = layout.getBehaviorSharedData(name);
const properties = sharedData.getProperties(project);
const propertiesSchema = propertiesMapToSchema(
properties,
sharedData => sharedData.getProperties(project),
(sharedData, name, value) =>
sharedData.updateProperty(name, value, project)
);
return (
!!propertiesSchema.length && (
<PropertiesEditor
schema={propertiesSchema}
instances={[sharedData]}
/>
)
);
});
return (
<Dialog
actions={actions}
@@ -88,6 +122,13 @@ export default class ScenePropertiesDialog extends Component {
this.props.onClose();
}}
/>
{!some(propertiesEditors) && (
<EmptyMessage>
Any additional properties will appear here if you add behaviors to
objects, like Physics behavior.
</EmptyMessage>
)}
{propertiesEditors}
{this.props.onOpenMoreSettings && (
<RaisedButton
label="Open advanced settings"

View File

@@ -279,9 +279,12 @@ export default class InstancesFullEditor extends Component {
};
_onInstancesMoved = instances => {
this.setState({
history: saveToHistory(this.state.history, this.props.initialInstances),
}, () => this.forceUpdatePropertiesEditor());
this.setState(
{
history: saveToHistory(this.state.history, this.props.initialInstances),
},
() => this.forceUpdatePropertiesEditor()
);
};
_onInstancesModified = instances => {
@@ -476,6 +479,11 @@ export default class InstancesFullEditor extends Component {
});
};
updateBehaviorsSharedData = () => {
const { layout, project } = this.props;
layout.updateBehaviorsSharedData(project);
};
forceUpdateObjectsList = () => {
if (this._objectsList) this._objectsList.forceUpdateList();
};
@@ -544,6 +552,7 @@ export default class InstancesFullEditor extends Component {
onEditObject={this.props.onEditObject || this.editObject}
onDeleteObject={this._onDeleteObject}
onRenameObject={this._onRenameObject}
onObjectPasted={() => this.updateBehaviorsSharedData()}
ref={objectsList => (this._objectsList = objectsList)}
/>
</MosaicWindow>
@@ -581,6 +590,7 @@ export default class InstancesFullEditor extends Component {
onCancel={() => this.editObject(null)}
onApply={() => {
this.editObject(null);
this.updateBehaviorsSharedData();
this.forceUpdateObjectsList();
}}
/>
@@ -672,6 +682,7 @@ export default class InstancesFullEditor extends Component {
/>
<ScenePropertiesDialog
open={!!this.state.scenePropertiesDialogOpen}
project={project}
layout={layout}
onClose={() => this.openSceneProperties(false)}
onApply={() => this.openSceneProperties(false)}

View File

@@ -3,6 +3,10 @@ import i18n from 'i18next';
i18n.init({
fallbackLng: 'en',
// allow keys to be phrases having `:`, `.`
nsSeparator: false,
keySeparator: false,
interpolation: {
escapeValue: false, // Not needed for react
},

View File

@@ -1,4 +1,4 @@
require('dotenv').config();
require('dotenv').config({ path: __dirname + '/.env' });
const electron = require('electron');
const app = electron.app; // Module to control application life.
const BrowserWindow = electron.BrowserWindow; // Module to create native browser window.

View File

@@ -1,6 +1,6 @@
{
"name": "gdevelop",
"version": "5.0.0-beta19",
"version": "5.0.0-beta21",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -215,6 +215,11 @@
"ms": "2.0.0"
}
},
"dotenv": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz",
"integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0="
},
"electron-editor-context-menu": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/electron-editor-context-menu/-/electron-editor-context-menu-1.1.1.tgz",

View File

@@ -2,7 +2,7 @@
"name": "gdevelop",
"productName": "GDevelop 5",
"description": "GDevelop 5 IDE running on the Electron runtime",
"version": "5.0.0-beta21",
"version": "5.0.0-beta22",
"author": "Florian Rival",
"license": "MIT",
"homepage": "http://compilgames.net",
@@ -18,6 +18,7 @@
"fs-extra": "^3.0.1",
"lodash.throttle": "^4.1.1",
"minimist": "^1.2.0",
"recursive-readdir": "^2.2.1"
"recursive-readdir": "^2.2.1",
"dotenv": "^4.0.0"
}
}

View File

@@ -664,7 +664,8 @@
"dotenv": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz",
"integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0="
"integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=",
"dev": true
},
"dotenv-expand": {
"version": "4.0.1",

View File

@@ -41,7 +41,6 @@
"shelljs": "^0.7.7"
},
"dependencies": {
"dotenv": "^4.0.0",
"electron-is": "^2.4.0"
}
}