Просмотр исходного кода

Merge pull request #9798 from msDestiny14/msDestiny14/snippet

[Gui Editor] Adding Loading and Saving
Pamela W 5 лет назад
Родитель
Сommit
e14e7ad081

+ 124 - 123
dist/preview release/what's new.md

@@ -1,123 +1,124 @@
-# 5.0.0
-
-## Major updates
-
-- Infinite Morph Targets: When supported (WebGL2+) you are no more limited to 4 morph targets per mesh ([Deltakosh](https://github.com/deltakosh))
-
-## Updates
-
-### General
-
-- Added static CenterToRef for vectors 2/3/4  ([aWeirdo](https://github.com/aWeirdo))
-- Added ability to view images (ktx2, png, jpg) to the sandbox. ([bghgary](https://github.com/bghgary))
-- Added optional smoothed normals for extruded procedural polygons. ([snagy](https://github.com/snagy))
-- Added support for infinite perspective cameras ([Deltakosh](https://github.com/deltakosh))
-- Added ability to enable/disable ArcRotateCamera zoom on multiTouch event ([NicolasBuecher](https://github.com/NicolasBuecher))
-- Moving button to shared uI folder.([msDestiny14](https://github.com/msDestiny14))
-- Moved sharedUI component to shared UI folder. ([msDestiny14](https://github.com/msDestiny14))
-- Added encapsulate and encapsulateBoundingInfo methods to BoundingInfo. ([Tolo789](https://github.com/Tolo789))
-- Added onLoadObservable to the textureDome class(es) ([RaananW](https://github.com/RaananW))
-- Modified InputManager to use DeviceInputSystem ([PolygonalSun](https://github.com/PolygonalSun))
-
-### Engine
-
-- Moved all instance data from Geometry to Mesh such that the same Geometry objects can be used by many meshes with instancing. Reduces memory consumption on CPU/GPU. ([breakin](https://github.com/breakin)
-
-### Loaders
-
-- Added support for EXT_meshopt_compression for glTF loader. ([zeux](https://github.com/zeux))
-- Increased KHR_materials_transmission render target texture default size. ([Drigax](https://github.com/drigax))
-- Changed glTF loader to remove empty animation groups if there are no animation channels loaded with the given options. ([bghgary](https://github.com/bghgary))
-- Update glTF validator to `2.0.0-dev.3.3`. ([bghgary](https://github.com/bghgary))
-- Added support for KHR_xmp_json_ld for glTF loader. ([Sebavan](https://github.com/sebavan/), [bghgary](https://github.com/bghgary))
-- Added a `OptimizeNormals` option to the OBJ loader to smooth lighting ([Popov72](https://github.com/Popov72))
-
-### Navigation
-
-- Added support for thin instances in navigation mesh creation ([CedricGuillemet](https://github.com/CedricGuillemet))
-- Added recast.d.ts definition file for recast.js ([CedricGuillemet](https://github.com/CedricGuillemet))
-
-### Materials
-
-- Added an `OcclusionMaterial` to simplify depth-only rendering of geometry ([rgerd](https://github.com/rgerd))
-- PrePass can now be used in `RenderTargets` speeding up effects like SSAO2 or MotionBlur ([CraigFeldspar](https://github.com/CraigFeldspar))
-- Added support for morph targets to `ShaderMaterial` ([Popov72](https://github.com/Popov72))
-
-### Inspector
-
-- Increased float precision to 4([msDestiny14](https://github.com/msDestiny14))
-- Added support for sounds in the inspector ([Deltakosh](https://github.com/deltakosh))
-
-### NME
-
-- Increased float precision to 4([msDestiny14](https://github.com/msDestiny14))
-- Added ability to make input node's properties visible in the properties of a custom frame ([msDestiny14](https://github.com/msDestiny14))
-
-### GUIEditor
-
-- Added GUI Editor project to master. ([msDestiny14](https://github.com/msDestiny14))
-- Moving GUI property tab components into GUIEditor. ([msDestiny14](https://github.com/msDestiny14))
-
-### GUI
-
-- Added a `FocusableButton` gui control to simplify creating menus with keyboard navigation ([Flux159](https://github.com/Flux159))
-- Added `focus()` and `blur()` functions for controls that implement `IFocusableControl` ([Flux159](https://github.com/Flux159))
-- Added `ToggleButton` GUI control ([kintz09](https://github.com/kintz09))
-- Added shorthand methods which set all padding values at once, named `setPadding` and `setPaddingInPixels`, to the control class  ([kintz09](https://github.com/kintz09))
-- Added two touch-enabled GUI controls, `TouchMeshButton3D` and `TouchHolographicButton`, added option on the WebXR hand tracking feature for enabling touch collisions ([rickfromwork](https://github.com/rickfromwork), [satyapoojasama](https://github.com/satyapoojasama))
-
-### WebXR
-
-- A browser error preventing the emulator to render scene is now correctly dealt with ([RaananW](https://github.com/RaananW))
-- Added a way to extend the XRSessionInit Object from inside of a feature ([RaananW](https://github.com/RaananW))
-- Added image tracking feature ([RaananW](https://github.com/RaananW))
-- Pointer Events of WebXR controllers have pointerType `xr` ([RaananW](https://github.com/RaananW))
-- better support for custom hand meshes ([RaananW](https://github.com/RaananW))
-- Allow disabling of the WebXRControllerPointerSelection feature as part of the WebXR Default Experience ([rgerd](https://github.com/rgerd))
-- Added two touch-enabled GUI controls, `TouchMeshButton3D` and `TouchHolographicButton`, added option on the WebXR hand tracking feature for enabling touch collisions ([rickfromwork](https://github.com/rickfromwork), [satyapoojasama](https://github.com/satyapoojasama))
-
-### Viewer
-
-- Fixed an issue with dual callback binding in case of a forced redraw ([#9608](https://github.com/BabylonJS/Babylon.js/issues/9608)) ([RaananW](https://github.com/RaananW))
-
-## Bugs
-
-- Fix issue with the Promise polyfill where a return value was expected from resolve() ([Deltakosh](https://github.com/deltakosh))
-- Fix ArcRotateCamera panning with axis decomposition ([CedricGuillemet](https://github.com/CedricGuillemet))
-- Fix an issue with keyboard control (re)attachment. ([#9411](https://github.com/BabylonJS/Babylon.js/issues/9411)) ([RaananW](https://github.com/RaananW))
-- Fix issue where PBRSpecularGlossiness materials were excluded from export [#9423](https://github.com/BabylonJS/Babylon.js/issues/9423)([Drigax](https://github.com/drigax))
-- Fix issue when scaling is reapplied with BoundingBoxGizmo and GizmoManager ([CedricGuillemet](https://github.com/CedricGuillemet))
-- Fix direct loading of a glTF string that has base64-encoded URI. ([bghgary](https://github.com/bghgary))
-- Fix capsule impostor size computation for ammojs ([CedricGuillemet](https://github.com/CedricGuillemet))
-- Fix crash of some node materials using instances on iOS ([Popov72](https://github.com/Popov72))
-- Fix the code generated for the NME gradient block ([Popov72](https://github.com/Popov72))
-- Fix ssao2RenderingPipeline for orthographic cameras ([Kesshi](https://github.com/Kesshi))
-- Fix mipmaps creation in the KTX2 decoder for non square textures ([Popov72](https://github.com/Popov72))
-- Fix detail map not working in WebGL1 ([Popov72](https://github.com/Popov72))
-- Fix ArcRotateCamera behaviour when panning is disabled on multiTouch event ([NicolasBuecher](https://github.com/NicolasBuecher))
-- Fix vertically interlaced stereoscopic rendering (`RIG_MODE_STEREOSCOPIC_INTERLACED`) not working (follow-up [#7425](https://github.com/BabylonJS/Babylon.js/issues/7425), [#8000](https://github.com/BabylonJS/Babylon.js/issues/8000)) ([foxxyz](https://github.com/foxxyz))
-- Fix accessibility of BaseCameraMouseWheelInput and BaseCameraPointersInput. They appear in documentation but were not available for include. ([mrdunk](https://github.com/mrdunk))
-- Fix function creation inside regularly called freeCameraMouseWheelInput method leading to excessive GC load. ([mrdunk](https://github.com/mrdunk))
-- Fix clip plane not reset to the rigth value when using mirrors ([Popov72](https://github.com/Popov72))
-- Fix lens flares not working in right handed system ([Popov72](https://github.com/Popov72))
-- Fix canvas not resized correctly in a multi-canvas scenario ([Popov72](https://github.com/Popov72))
-- Fix NaN values returned by `GetAngleBetweenVectors` when vectors are the same or directly opposite ([Popov72](https://github.com/Popov72))
-- Fix 404 occurring on some pictures in some cases when using particle systems ([Popov72](https://github.com/Popov72))
-- Fix PrePass bugs with transparency ([CraigFeldspar](https://github.com/CraigFeldspar))
-- Fix PrePass bugs with layers ([CraigFeldspar](https://github.com/CraigFeldspar))
-- Fix SSAO2 with PrePass sometimes causing colors brighter than they should be ([CraigFeldspar](https://github.com/CraigFeldspar))
-- Fix PostProcess sharing between cameras/renderTargets, that would create/destroy a texture on every frame ([CraigFeldspar](https://github.com/CraigFeldspar))
-- Fix for DualSense gamepads being incorrectly read as DualShock gamepads ([PolygonalSun](https://github.com/PolygonalSun))
-- Fix for warning in chrome about passive wheel events ([#9777](https://github.com/BabylonJS/Babylon.js/pull/9777)) ([kaliatech](https://github.com/kaliatech))
-- Fix crash when cloning material in `AssetContainer.instantiateModelsToScene` when mesh is an instanced mesh ([Popov72](https://github.com/Popov72))
-- Fix issue with NinePatch displaying half pixel gaps between slices on Firefox browsers. ([Pryme8](https://github.com/Pryme8))
-
-## Breaking changes
-
-- [List of breaking changes introduced by ou compatibility with WebGPU](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges)
-  - [ReadPixels and ProceduralTexture.getContent are now async](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges#readpixels-is-now-asynchronous)
-  - [Shader support differences](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges#shader-code-differences)
-- Use both `mesh.visibility` and `material.alpha` values to compute the global alpha value used by the soft transparent shadow rendering code. Formerly was only using `mesh.visibility` ([Popov72](https://github.com/Popov72))
-- Depth renderer: don't render mesh if `infiniteDistance = true` or if `material.disableDepthWrite = true` ([Popov72](https://github.com/Popov72))
-- Mesh.createInstance no longer make a unique Geometry for the Mesh so updating one Geometry can affect more meshes than before. Use Mesh.makeUniqueGeometry for old behaviour. ([breakin](https://github.com/breakin))
-- Ammo.js needs to be initialized before creating the plugin with `await Ammo();` since Ammo introduced an async init in their library. ([sebavan](https://github.com/sebavan))
+# 5.0.0
+
+## Major updates
+
+- Infinite Morph Targets: When supported (WebGL2+) you are no more limited to 4 morph targets per mesh ([Deltakosh](https://github.com/deltakosh))
+
+## Updates
+
+### General
+
+- Added static CenterToRef for vectors 2/3/4  ([aWeirdo](https://github.com/aWeirdo))
+- Added ability to view images (ktx2, png, jpg) to the sandbox. ([bghgary](https://github.com/bghgary))
+- Added optional smoothed normals for extruded procedural polygons. ([snagy](https://github.com/snagy))
+- Added support for infinite perspective cameras ([Deltakosh](https://github.com/deltakosh))
+- Added ability to enable/disable ArcRotateCamera zoom on multiTouch event ([NicolasBuecher](https://github.com/NicolasBuecher))
+- Moving button to shared uI folder.([msDestiny14](https://github.com/msDestiny14))
+- Moved sharedUI component to shared UI folder. ([msDestiny14](https://github.com/msDestiny14))
+- Added encapsulate and encapsulateBoundingInfo methods to BoundingInfo. ([Tolo789](https://github.com/Tolo789))
+- Added onLoadObservable to the textureDome class(es) ([RaananW](https://github.com/RaananW))
+- Modified InputManager to use DeviceInputSystem ([PolygonalSun](https://github.com/PolygonalSun))
+
+### Engine
+
+- Moved all instance data from Geometry to Mesh such that the same Geometry objects can be used by many meshes with instancing. Reduces memory consumption on CPU/GPU. ([breakin](https://github.com/breakin)
+
+### Loaders
+
+- Added support for EXT_meshopt_compression for glTF loader. ([zeux](https://github.com/zeux))
+- Increased KHR_materials_transmission render target texture default size. ([Drigax](https://github.com/drigax))
+- Changed glTF loader to remove empty animation groups if there are no animation channels loaded with the given options. ([bghgary](https://github.com/bghgary))
+- Update glTF validator to `2.0.0-dev.3.3`. ([bghgary](https://github.com/bghgary))
+- Added support for KHR_xmp_json_ld for glTF loader. ([Sebavan](https://github.com/sebavan/), [bghgary](https://github.com/bghgary))
+- Added a `OptimizeNormals` option to the OBJ loader to smooth lighting ([Popov72](https://github.com/Popov72))
+
+### Navigation
+
+- Added support for thin instances in navigation mesh creation ([CedricGuillemet](https://github.com/CedricGuillemet))
+- Added recast.d.ts definition file for recast.js ([CedricGuillemet](https://github.com/CedricGuillemet))
+
+### Materials
+
+- Added an `OcclusionMaterial` to simplify depth-only rendering of geometry ([rgerd](https://github.com/rgerd))
+- PrePass can now be used in `RenderTargets` speeding up effects like SSAO2 or MotionBlur ([CraigFeldspar](https://github.com/CraigFeldspar))
+- Added support for morph targets to `ShaderMaterial` ([Popov72](https://github.com/Popov72))
+
+### Inspector
+
+- Increased float precision to 4([msDestiny14](https://github.com/msDestiny14))
+- Added support for sounds in the inspector ([Deltakosh](https://github.com/deltakosh))
+
+### NME
+
+- Increased float precision to 4([msDestiny14](https://github.com/msDestiny14))
+- Added ability to make input node's properties visible in the properties of a custom frame ([msDestiny14](https://github.com/msDestiny14))
+
+### GUIEditor
+
+- Added GUI Editor project to master. ([msDestiny14](https://github.com/msDestiny14))
+- Moving GUI property tab components into GUIEditor. ([msDestiny14](https://github.com/msDestiny14))
+- Adding basic saving and loading funtionality. ([msDestiny14](https://github.com/msDestiny14))
+
+### GUI
+
+- Added a `FocusableButton` gui control to simplify creating menus with keyboard navigation ([Flux159](https://github.com/Flux159))
+- Added `focus()` and `blur()` functions for controls that implement `IFocusableControl` ([Flux159](https://github.com/Flux159))
+- Added `ToggleButton` GUI control ([kintz09](https://github.com/kintz09))
+- Added shorthand methods which set all padding values at once, named `setPadding` and `setPaddingInPixels`, to the control class  ([kintz09](https://github.com/kintz09))
+- Added two touch-enabled GUI controls, `TouchMeshButton3D` and `TouchHolographicButton`, added option on the WebXR hand tracking feature for enabling touch collisions ([rickfromwork](https://github.com/rickfromwork), [satyapoojasama](https://github.com/satyapoojasama))
+
+### WebXR
+
+- A browser error preventing the emulator to render scene is now correctly dealt with ([RaananW](https://github.com/RaananW))
+- Added a way to extend the XRSessionInit Object from inside of a feature ([RaananW](https://github.com/RaananW))
+- Added image tracking feature ([RaananW](https://github.com/RaananW))
+- Pointer Events of WebXR controllers have pointerType `xr` ([RaananW](https://github.com/RaananW))
+- better support for custom hand meshes ([RaananW](https://github.com/RaananW))
+- Allow disabling of the WebXRControllerPointerSelection feature as part of the WebXR Default Experience ([rgerd](https://github.com/rgerd))
+- Added two touch-enabled GUI controls, `TouchMeshButton3D` and `TouchHolographicButton`, added option on the WebXR hand tracking feature for enabling touch collisions ([rickfromwork](https://github.com/rickfromwork), [satyapoojasama](https://github.com/satyapoojasama))
+
+### Viewer
+
+- Fixed an issue with dual callback binding in case of a forced redraw ([#9608](https://github.com/BabylonJS/Babylon.js/issues/9608)) ([RaananW](https://github.com/RaananW))
+
+## Bugs
+
+- Fix issue with the Promise polyfill where a return value was expected from resolve() ([Deltakosh](https://github.com/deltakosh))
+- Fix ArcRotateCamera panning with axis decomposition ([CedricGuillemet](https://github.com/CedricGuillemet))
+- Fix an issue with keyboard control (re)attachment. ([#9411](https://github.com/BabylonJS/Babylon.js/issues/9411)) ([RaananW](https://github.com/RaananW))
+- Fix issue where PBRSpecularGlossiness materials were excluded from export [#9423](https://github.com/BabylonJS/Babylon.js/issues/9423)([Drigax](https://github.com/drigax))
+- Fix issue when scaling is reapplied with BoundingBoxGizmo and GizmoManager ([CedricGuillemet](https://github.com/CedricGuillemet))
+- Fix direct loading of a glTF string that has base64-encoded URI. ([bghgary](https://github.com/bghgary))
+- Fix capsule impostor size computation for ammojs ([CedricGuillemet](https://github.com/CedricGuillemet))
+- Fix crash of some node materials using instances on iOS ([Popov72](https://github.com/Popov72))
+- Fix the code generated for the NME gradient block ([Popov72](https://github.com/Popov72))
+- Fix ssao2RenderingPipeline for orthographic cameras ([Kesshi](https://github.com/Kesshi))
+- Fix mipmaps creation in the KTX2 decoder for non square textures ([Popov72](https://github.com/Popov72))
+- Fix detail map not working in WebGL1 ([Popov72](https://github.com/Popov72))
+- Fix ArcRotateCamera behaviour when panning is disabled on multiTouch event ([NicolasBuecher](https://github.com/NicolasBuecher))
+- Fix vertically interlaced stereoscopic rendering (`RIG_MODE_STEREOSCOPIC_INTERLACED`) not working (follow-up [#7425](https://github.com/BabylonJS/Babylon.js/issues/7425), [#8000](https://github.com/BabylonJS/Babylon.js/issues/8000)) ([foxxyz](https://github.com/foxxyz))
+- Fix accessibility of BaseCameraMouseWheelInput and BaseCameraPointersInput. They appear in documentation but were not available for include. ([mrdunk](https://github.com/mrdunk))
+- Fix function creation inside regularly called freeCameraMouseWheelInput method leading to excessive GC load. ([mrdunk](https://github.com/mrdunk))
+- Fix clip plane not reset to the rigth value when using mirrors ([Popov72](https://github.com/Popov72))
+- Fix lens flares not working in right handed system ([Popov72](https://github.com/Popov72))
+- Fix canvas not resized correctly in a multi-canvas scenario ([Popov72](https://github.com/Popov72))
+- Fix NaN values returned by `GetAngleBetweenVectors` when vectors are the same or directly opposite ([Popov72](https://github.com/Popov72))
+- Fix 404 occurring on some pictures in some cases when using particle systems ([Popov72](https://github.com/Popov72))
+- Fix PrePass bugs with transparency ([CraigFeldspar](https://github.com/CraigFeldspar))
+- Fix PrePass bugs with layers ([CraigFeldspar](https://github.com/CraigFeldspar))
+- Fix SSAO2 with PrePass sometimes causing colors brighter than they should be ([CraigFeldspar](https://github.com/CraigFeldspar))
+- Fix PostProcess sharing between cameras/renderTargets, that would create/destroy a texture on every frame ([CraigFeldspar](https://github.com/CraigFeldspar))
+- Fix for DualSense gamepads being incorrectly read as DualShock gamepads ([PolygonalSun](https://github.com/PolygonalSun))
+- Fix for warning in chrome about passive wheel events ([#9777](https://github.com/BabylonJS/Babylon.js/pull/9777)) ([kaliatech](https://github.com/kaliatech))
+- Fix crash when cloning material in `AssetContainer.instantiateModelsToScene` when mesh is an instanced mesh ([Popov72](https://github.com/Popov72))
+- Fix issue with NinePatch displaying half pixel gaps between slices on Firefox browsers. ([Pryme8](https://github.com/Pryme8))
+
+## Breaking changes
+
+- [List of breaking changes introduced by ou compatibility with WebGPU](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges)
+  - [ReadPixels and ProceduralTexture.getContent are now async](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges#readpixels-is-now-asynchronous)
+  - [Shader support differences](https://doc.babylonjs.com/advanced_topics/webGPU/webGPUBreakingChanges#shader-code-differences)
+- Use both `mesh.visibility` and `material.alpha` values to compute the global alpha value used by the soft transparent shadow rendering code. Formerly was only using `mesh.visibility` ([Popov72](https://github.com/Popov72))
+- Depth renderer: don't render mesh if `infiniteDistance = true` or if `material.disableDepthWrite = true` ([Popov72](https://github.com/Popov72))
+- Mesh.createInstance no longer make a unique Geometry for the Mesh so updating one Geometry can affect more meshes than before. Use Mesh.makeUniqueGeometry for old behaviour. ([breakin](https://github.com/breakin))
+- Ammo.js needs to be initialized before creating the plugin with `await Ammo();` since Ammo introduced an async init in their library. ([sebavan](https://github.com/sebavan))

+ 91 - 154
guiEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -1,17 +1,16 @@
-
 import * as React from "react";
-import { GlobalState } from '../../globalState';
-import { Nullable } from 'babylonjs/types';
-import { ButtonLineComponent } from '../../sharedUiComponents/lines/buttonLineComponent';
-import { LineContainerComponent } from '../../sharedUiComponents/lines/lineContainerComponent';
-import { FileButtonLineComponent } from '../../sharedUiComponents/lines/fileButtonLineComponent';
-import { Tools } from 'babylonjs/Misc/tools';
-import { CheckBoxLineComponent } from '../../sharedUiComponents/lines/checkBoxLineComponent';
-import { DataStorage } from 'babylonjs/Misc/dataStorage';
-import { GUINode } from '../../diagram/guiNode';
-import { Observer } from 'babylonjs/Misc/observable';
+import { GlobalState } from "../../globalState";
+import { Nullable } from "babylonjs/types";
+import { ButtonLineComponent } from "../../sharedUiComponents/lines/buttonLineComponent";
+import { LineContainerComponent } from "../../sharedUiComponents/lines/lineContainerComponent";
+import { FileButtonLineComponent } from "../../sharedUiComponents/lines/fileButtonLineComponent";
+import { Tools } from "babylonjs/Misc/tools";
+import { CheckBoxLineComponent } from "../../sharedUiComponents/lines/checkBoxLineComponent";
+import { DataStorage } from "babylonjs/Misc/dataStorage";
+import { GUINode } from "../../diagram/guiNode";
+import { Observer } from "babylonjs/Misc/observable";
 import { TextLineComponent } from "../../sharedUiComponents/lines/textLineComponent";
-import { SerializationTools } from "../../serializationTools";
+import { StringTools } from "../../sharedUiComponents/stringTools";
 import { Engine } from "babylonjs/Engines/engine";
 import { LockObject } from "../../sharedUiComponents/tabs/propertyGrids/lockObject";
 import { SliderPropertyGridComponent } from "../../sharedUiComponents/tabs/propertyGrids/gui/sliderPropertyGridComponent";
@@ -45,6 +44,7 @@ import { EllipsePropertyGridComponent } from "../../sharedUiComponents/tabs/prop
 import { CheckboxPropertyGridComponent } from "../../sharedUiComponents/tabs/propertyGrids/gui/checkboxPropertyGridComponent";
 import { Control } from "babylonjs-gui/2D/controls/control";
 import { ControlPropertyGridComponent } from "../../sharedUiComponents/tabs/propertyGrids/gui/controlPropertyGridComponent";
+import { AdvancedDynamicTexture } from "babylonjs-gui/2D/advancedDynamicTexture";
 
 require("./propertyTab.scss");
 
@@ -54,7 +54,7 @@ interface IPropertyTabComponentProps {
 
 interface IPropertyTabComponentState {
     currentNode: Nullable<GUINode>;
- }
+}
 
 export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, IPropertyTabComponentState> {
     private _onBuiltObserver: Nullable<Observer<void>>;
@@ -63,7 +63,7 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
     constructor(props: IPropertyTabComponentProps) {
         super(props);
 
-        this.state = { currentNode: null};
+        this.state = { currentNode: null };
     }
 
     timerRefresh() {
@@ -76,7 +76,7 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
         this._timerIntervalId = window.setInterval(() => this.timerRefresh(), 500);
         this.props.globalState.onSelectionChangedObservable.add((selection) => {
             if (selection instanceof GUINode) {
-                this.setState({ currentNode: selection});
+                this.setState({ currentNode: selection });
             } else {
                 this.setState({ currentNode: null });
             }
@@ -92,210 +92,148 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
         this.props.globalState.onBuiltObservable.remove(this._onBuiltObserver);
     }
 
-
     load(file: File) {
-        Tools.ReadFile(file, (data) => {
-            let decoder = new TextDecoder("utf-8");
-            SerializationTools.Deserialize(JSON.parse(decoder.decode(data)), this.props.globalState);
-
-            this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
-        }, undefined, true);
-    }
-
-    loadFrame(file: File) {
-        Tools.ReadFile(file, (data) => {
-            // get Frame Data from file
-            //let decoder = new TextDecoder("utf-8");
-           // const frameData = JSON.parse(decoder.decode(data));
-           // SerializationTools.AddFrameToMaterial(frameData, this.props.globalState, this.props.globalState.nodeMaterial);
-        }, undefined, true);
+        Tools.ReadFile(
+            file,
+            (data) => {
+                const decoder = new TextDecoder("utf-8");
+                this.props.globalState.workbench.loadFromJson(JSON.parse(decoder.decode(data)));
+
+                this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
+            },
+            undefined,
+            true
+        );
     }
 
     save() {
-        //let json = SerializationTools.Serialize(this.props.globalState.nodeMaterial, this.props.globalState);
-        //StringTools.DownloadAsFile(this.props.globalState.hostDocument, json, "nodeMaterial.json");
-    }
-
-    customSave() {
-        /*this.props.globalState.onLogRequiredObservable.notifyObservers({message: "Saving your material to Babylon.js snippet server...", isError: false});
-        this.props.globalState.customSave!.action(SerializationTools.Serialize(this.props.globalState.nodeMaterial, this.props.globalState)).then(() => {
-            this.props.globalState.onLogRequiredObservable.notifyObservers({message: "Material saved successfully", isError: false});
-        }).catch((err) => {
-            this.props.globalState.onLogRequiredObservable.notifyObservers({message: err, isError: true});
-        });*/
+        const json = JSON.stringify(this.props.globalState.guiTexture.serializeContent());
+        StringTools.DownloadAsFile(this.props.globalState.hostDocument, json, "guiTexture.json");
     }
 
     saveToSnippetServer() {
-        /*const material = this.props.globalState.nodeMaterial;
-        const xmlHttp = new XMLHttpRequest();
-
-        let json = SerializationTools.Serialize(material, this.props.globalState);
+        const adt = this.props.globalState.guiTexture;
+        const content = JSON.stringify(adt.serializeContent());
 
+        const xmlHttp = new XMLHttpRequest();
         xmlHttp.onreadystatechange = () => {
             if (xmlHttp.readyState == 4) {
                 if (xmlHttp.status == 200) {
-                    var snippet = JSON.parse(xmlHttp.responseText);
-                    const oldId = material.snippetId;
-                    material.snippetId = snippet.id;
+                    const snippet = JSON.parse(xmlHttp.responseText);
+                    const oldId = adt.snippetId;
+                    adt.snippetId = snippet.id;
                     if (snippet.version && snippet.version != "0") {
-                        material.snippetId += "#" + snippet.version;
+                        adt.snippetId += "#" + snippet.version;
                     }
-
                     this.forceUpdate();
                     if (navigator.clipboard) {
-                        navigator.clipboard.writeText(material.snippetId);
+                        navigator.clipboard.writeText(adt.snippetId);
                     }
 
-                    let windowAsAny = window as any;
+                    const windowAsAny = window as any;
 
                     if (windowAsAny.Playground && oldId) {
                         windowAsAny.Playground.onRequestCodeChangeObservable.notifyObservers({
                             regex: new RegExp(oldId, "g"),
-                            replace: material.snippetId
+                            replace: `parseFromSnippetAsync("${adt.snippetId}`,
                         });
                     }
 
-                    this.props.globalState.hostDocument.defaultView!.alert("NodeMaterial saved with ID: " + material.snippetId + " (please note that the id was also saved to your clipboard)");
-
-                }
-                else {
-                    this.props.globalState.hostDocument.defaultView!.alert(`Unable to save your node material. It may be too large (${(dataToSend.payload.length / 1024).toFixed(2)} KB) because of embedded textures. Please reduce texture sizes or point to a specific url instead of embedding them and try again.`);
+                    alert("GUI saved with ID: " + adt.snippetId + " (please note that the id was also saved to your clipboard)");
+                } else {
+                    alert("Unable to save your GUI");
                 }
             }
         };
 
-        xmlHttp.open("POST", NodeMaterial.SnippetUrl + (material.snippetId ? "/" + material.snippetId : ""), true);
+        xmlHttp.open("POST", AdvancedDynamicTexture.SnippetUrl + (adt.snippetId ? "/" + adt.snippetId : ""), true);
         xmlHttp.setRequestHeader("Content-Type", "application/json");
 
-        var dataToSend = {
-            payload : JSON.stringify({
-                nodeMaterial: json
+        const dataToSend = {
+            payload: JSON.stringify({
+                gui: content,
             }),
             name: "",
             description: "",
-            tags: ""
+            tags: "",
         };
 
-        xmlHttp.send(JSON.stringify(dataToSend));*/
+        xmlHttp.send(JSON.stringify(dataToSend));
     }
 
     loadFromSnippet() {
-        /*const material = this.props.globalState.nodeMaterial;
-        const scene = material.getScene();
-
-        let snippedID = window.prompt("Please enter the snippet ID to use");
+        const snippedID = window.prompt("Please enter the snippet ID to use");
 
         if (!snippedID) {
             return;
         }
-
-        this.props.globalState.onSelectionChangedObservable.notifyObservers(null);
-
-        NodeMaterial.ParseFromSnippetAsync(snippedID, scene, "", material).then(() => {
-            material.build();
-            if (!this.changeMode(this.props.globalState.nodeMaterial!.mode, true, false)) {
-                this.props.globalState.onResetRequiredObservable.notifyObservers();
-            }
-        }).catch((err) => {
-            this.props.globalState.hostDocument.defaultView!.alert("Unable to load your node material: " + err);
-        });*/
+        this.props.globalState.workbench.loadFromSnippet(snippedID);
     }
 
-    renderProperties()
-    {
-        var className = this.state.currentNode?.guiControl.getClassName();
+    renderProperties() {
+        const className = this.state.currentNode?.guiControl.getClassName();
         switch (className) {
             case "TextBlock": {
                 const textBlock = this.state.currentNode?.guiControl as TextBlock;
-                return (<TextBlockPropertyGridComponent textBlock={textBlock}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <TextBlockPropertyGridComponent textBlock={textBlock} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "InputText": {
                 const inputText = this.state.currentNode?.guiControl as InputText;
-                return (<InputTextPropertyGridComponent inputText={inputText}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <InputTextPropertyGridComponent inputText={inputText} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "ColorPicker": {
                 const colorPicker = this.state.currentNode?.guiControl as ColorPicker;
-                return (<ColorPickerPropertyGridComponent colorPicker={colorPicker}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <ColorPickerPropertyGridComponent colorPicker={colorPicker} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "Image": {
                 const image = this.state.currentNode?.guiControl as Image;
-                return (<ImagePropertyGridComponent image={image}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <ImagePropertyGridComponent image={image} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "Slider": {
                 const slider = this.state.currentNode?.guiControl as Slider;
-                return (<SliderPropertyGridComponent slider={slider}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <SliderPropertyGridComponent slider={slider} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "ImageBasedSlider": {
                 const imageBasedSlider = this.state.currentNode?.guiControl as ImageBasedSlider;
-                return (<ImageBasedSliderPropertyGridComponent imageBasedSlider={imageBasedSlider}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <ImageBasedSliderPropertyGridComponent imageBasedSlider={imageBasedSlider} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "Rectangle": {
                 const rectangle = this.state.currentNode?.guiControl as Rectangle;
-                return (<RectanglePropertyGridComponent rectangle={rectangle}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <RectanglePropertyGridComponent rectangle={rectangle} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "StackPanel": {
                 const stackPanel = this.state.currentNode?.guiControl as StackPanel;
-                return (<StackPanelPropertyGridComponent stackPanel={stackPanel}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <StackPanelPropertyGridComponent stackPanel={stackPanel} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "Grid": {
                 const grid = this.state.currentNode?.guiControl as Grid;
-                return (<GridPropertyGridComponent grid={grid}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <GridPropertyGridComponent grid={grid} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "ScrollViewer": {
                 const scrollViewer = this.state.currentNode?.guiControl as ScrollViewer;
-                return (<ScrollViewerPropertyGridComponent scrollViewer={scrollViewer}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <ScrollViewerPropertyGridComponent scrollViewer={scrollViewer} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "Ellipse": {
                 const ellipse = this.state.currentNode?.guiControl as Ellipse;
-                return (<EllipsePropertyGridComponent ellipse={ellipse}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <EllipsePropertyGridComponent ellipse={ellipse} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "Checkbox": {
                 const checkbox = this.state.currentNode?.guiControl as Checkbox;
-                return (<CheckboxPropertyGridComponent checkbox={checkbox}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <CheckboxPropertyGridComponent checkbox={checkbox} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "RadioButton": {
                 const radioButton = this.state.currentNode?.guiControl as RadioButton;
-                return (<RadioButtonPropertyGridComponent radioButton={radioButton}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <RadioButtonPropertyGridComponent radioButton={radioButton} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
             case "Line": {
                 const line = this.state.currentNode?.guiControl as Line;
-                return (<LinePropertyGridComponent line={line}
-                    lockObject={this._lockObject}
-                    onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+                return <LinePropertyGridComponent line={line} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
             }
         }
 
         if (className !== "") {
             const control = this.state.currentNode?.guiControl as Control;
-            return (<ControlPropertyGridComponent control={control}
-                lockObject={this._lockObject}
-                onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />);
+            return <ControlPropertyGridComponent control={control} lockObject={this._lockObject} onPropertyChangedObservable={this.props.globalState.onPropertyChangedObservable} />;
         }
         return null;
     }
@@ -306,9 +244,7 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
                 <div id="propertyTab">
                     <div id="header">
                         <img id="logo" src="https://www.babylonjs.com/Assets/logo-babylonjs-social-twitter.png" />
-                        <div id="title">
-                            GUI EDITOR
-                        </div>
+                        <div id="title">GUI EDITOR</div>
                     </div>
                     {this.renderProperties()}
                 </div>
@@ -319,20 +255,22 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
             <div id="propertyTab">
                 <div id="header">
                     <img id="logo" src="https://www.babylonjs.com/Assets/logo-babylonjs-social-twitter.png" />
-                    <div id="title">
-                        GUI EDITOR
-                    </div>
+                    <div id="title">GUI EDITOR</div>
                 </div>
                 <div>
                     <LineContainerComponent title="GENERAL">
-                        <TextLineComponent label="Version" value={Engine.Version}/>
-                        <TextLineComponent label="Help" value="doc.babylonjs.com" underline={true} onLink={() => window.open('https://doc.babylonjs.com', '_blank')}/>
-                        <ButtonLineComponent label="Reset to default" onClick={() => {
-                            this.props.globalState.onResetRequiredObservable.notifyObservers();
-                        }} />
+                        <TextLineComponent label="Version" value={Engine.Version} />
+                        <TextLineComponent label="Help" value="doc.babylonjs.com" underline={true} onLink={() => window.open("https://doc.babylonjs.com", "_blank")} />
+                        <ButtonLineComponent
+                            label="Reset to default"
+                            onClick={() => {
+                                this.props.globalState.onResetRequiredObservable.notifyObservers();
+                            }}
+                        />
                     </LineContainerComponent>
                     <LineContainerComponent title="OPTIONS">
-                        <CheckBoxLineComponent label="Show grid"
+                        <CheckBoxLineComponent
+                            label="Show grid"
                             isSelected={() => DataStorage.ReadBoolean("ShowGrid", true)}
                             onSelect={(value: boolean) => {
                                 DataStorage.WriteBoolean("ShowGrid", value);
@@ -341,27 +279,26 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
                     </LineContainerComponent>
                     <LineContainerComponent title="FILE">
                         <FileButtonLineComponent label="Load" onClick={(file) => this.load(file)} accept=".json" />
-                        <ButtonLineComponent label="Save" onClick={() => {
-                            this.save();
-                        }} />
-                        {
-                            this.props.globalState.customSave &&
-                            <ButtonLineComponent label={this.props.globalState.customSave!.label} onClick={() => {
-                                this.customSave();
-                            }} />
-                        }
+                        <ButtonLineComponent
+                            label="Save"
+                            onClick={() => {
+                                this.save();
+                            }}
+                        />
                     </LineContainerComponent>
                     {
-                        !this.props.globalState.customSave &&
                         <LineContainerComponent title="SNIPPET">
                             <ButtonLineComponent label="Load from snippet server" onClick={() => this.loadFromSnippet()} />
-                            <ButtonLineComponent label="Save to snippet server" onClick={() => {
-                                this.saveToSnippetServer();
-                            }} />
+                            <ButtonLineComponent
+                                label="Save to snippet server"
+                                onClick={() => {
+                                    this.saveToSnippetServer();
+                                }}
+                            />
                         </LineContainerComponent>
                     }
                 </div>
             </div>
         );
     }
-}
+}

+ 62 - 38
guiEditor/src/diagram/guiNode.ts

@@ -1,25 +1,27 @@
-import { GlobalState } from '../globalState';
-import { Nullable } from 'babylonjs/types';
-import { Observer } from 'babylonjs/Misc/observable';
-import { WorkbenchComponent, FramePortData } from './workbench';
-import { Control } from 'babylonjs-gui/2D/controls/control';
-import { Vector2 } from 'babylonjs/Maths/math.vector';
-
+import { GlobalState } from "../globalState";
+import { Nullable } from "babylonjs/types";
+import { Observer } from "babylonjs/Misc/observable";
+import { WorkbenchComponent, FramePortData } from "./workbench";
+import { Control } from "babylonjs-gui/2D/controls/control";
+import { Vector2 } from "babylonjs/Maths/math.vector";
+import { Container } from "babylonjs-gui/2D/controls/container";
 
 export class GUINode {
     private _x = 0;
     private _y = 0;
     private _gridAlignedX = 0;
-    private _gridAlignedY = 0;    
+    private _gridAlignedY = 0;
     private _globalState: GlobalState;
-    private _onSelectionChangedObserver: Nullable<Observer<Nullable<GUINode | FramePortData>>>;  
-    private _onSelectionBoxMovedObserver: Nullable<Observer<ClientRect | DOMRect>>;   
-    private _onUpdateRequiredObserver: Nullable<Observer<void>>;  
-    private _ownerCanvas: WorkbenchComponent; 
+    private _onSelectionChangedObserver: Nullable<Observer<Nullable<GUINode | FramePortData>>>;
+    private _onSelectionBoxMovedObserver: Nullable<Observer<ClientRect | DOMRect>>;
+    private _onUpdateRequiredObserver: Nullable<Observer<void>>;
+    private _ownerCanvas: WorkbenchComponent;
     private _isSelected: boolean;
     private _isVisible = true;
     private _enclosingFrameId = -1;
 
+    public children: GUINode[] = [];
+
     public get isVisible() {
         return this._isVisible;
     }
@@ -45,7 +47,7 @@ export class GUINode {
             return;
         }
         this._x = value;
-        
+
         this._gridAlignedX = this._ownerCanvas.getGridPosition(value);
     }
 
@@ -95,42 +97,40 @@ export class GUINode {
         this._isSelected = value;
 
         if (value) {
-            this._globalState.onSelectionChangedObservable.notifyObservers(this);  
+            this._globalState.onSelectionChangedObservable.notifyObservers(this);
         }
     }
 
     public constructor(globalState: GlobalState, public guiControl: Control) {
         this._globalState = globalState;
         this._ownerCanvas = this._globalState.workbench;
-        
-        guiControl.onPointerUpObservable.add(evt => {
+        this.x = guiControl.leftInPixels;
+        this.y = guiControl.topInPixels;
+        guiControl.onPointerUpObservable.add((evt) => {
             this.clicked = false;
             console.log("up");
         });
 
-        guiControl.onPointerDownObservable.add( evt => {
+        guiControl.onPointerDownObservable.add((evt) => {
+            if (!this._ownerCanvas.isUp) return;
             this.clicked = true;
             this.isSelected = true;
             console.log("down");
-        }
-        );
+            this._ownerCanvas.isUp = false;
+        });
 
-        guiControl.onPointerEnterObservable.add( evt => {
+        guiControl.onPointerEnterObservable.add((evt) => {
             this._ownerCanvas.isOverGUINode = true;
             console.log("in");
-        }
-        );
+        });
 
-        guiControl.onPointerOutObservable.add( evt => {
+        guiControl.onPointerOutObservable.add((evt) => {
             this._ownerCanvas.isOverGUINode = false;
             console.log("out");
-        }
-        );
-
-        //TODO: Implement
-        this._onSelectionBoxMovedObserver = this._globalState.onSelectionBoxMoved.add(rect1 => {
         });
 
+        //TODO: Implement
+        this._onSelectionBoxMovedObserver = this._globalState.onSelectionBoxMoved.add((rect1) => {});
     }
 
     public cleanAccumulation(useCeil = false) {
@@ -139,28 +139,52 @@ export class GUINode {
     }
 
     public clicked: boolean;
-    public _onMove(evt: Vector2, startPos: Vector2) {
-       
-        if(!this.clicked) return false;
+    public _onMove(evt: Vector2, startPos: Vector2, ignorClick: boolean = false) {
+        if (!this.clicked && !ignorClick) return false;
         console.log("moving");
 
         //TODO: Implement move with zoom factor.
-        let newX = (evt.x - startPos.x) ;// / this._ownerCanvas.zoom;
-        let newY = (evt.y - startPos.y) ;// / this._ownerCanvas.zoom;
+        let newX = evt.x - startPos.x; // / this._ownerCanvas.zoom;
+        let newY = evt.y - startPos.y; // / this._ownerCanvas.zoom;
 
         this.x += newX;
-        this.y += newY;  
+        this.y += newY;
+
+        this.children.forEach((child) => {
+            child._onMove(evt, startPos, true);
+        });
 
         return true;
         //evt.stopPropagation();
     }
 
-    public updateVisual()
-    {
+    public updateVisual() {
         this.guiControl.leftInPixels = this.x;
         this.guiControl.topInPixels = this.y;
     }
 
+    private _isContainer() {
+        switch (this.guiControl.typeName) {
+            case "Button":
+            case "StackPanel":
+            case "Rectangle":
+            case "Ellipse":
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    public addGui(childNode: GUINode) {
+        if (!this._isContainer) return;
+        this.children.push(childNode);
+        (this.guiControl as Container).addControl(childNode.guiControl);
+
+        //adjust the position to be relative
+        //childNode.x = this.x - childNode.x;
+        //childNode.y = this.y - childNode.y;
+    }
+
     public dispose() {
         // notify frame observers that this node is being deleted
         this._globalState.onGuiNodeRemovalObservable.notifyObservers(this);
@@ -177,6 +201,6 @@ export class GUINode {
             this._globalState.onSelectionBoxMoved.remove(this._onSelectionBoxMovedObserver);
         }
 
-        this.guiControl.dispose();   
+        this.guiControl.dispose();
     }
-}
+}

+ 0 - 113
guiEditor/src/diagram/properties/genericNodePropertyComponent.tsx

@@ -1,113 +0,0 @@
-
-import * as React from "react";
-import { LineContainerComponent } from '../../sharedUiComponents/lines/lineContainerComponent';
-import { IPropertyComponentProps } from './propertyComponentProps';
-import { CheckBoxLineComponent } from '../../sharedUiComponents/lines/checkBoxLineComponent';
-import { FloatLineComponent } from '../../sharedComponents/floatLineComponent';
-import { SliderLineComponent } from '../../sharedComponents/sliderLineComponent';
-import { PropertyTypeForEdition, IPropertyDescriptionForEdition } from 'babylonjs/Materials/Node/nodeMaterialDecorator';
-
-export class GenericPropertyComponent extends React.Component<IPropertyComponentProps> {
-    constructor(props: IPropertyComponentProps) {
-        super(props);
-    }
-
-    render() {
-        return (
-            <>
-                <GeneralPropertyTabComponent globalState={this.props.globalState} guiControl={this.props.guiControl}/>
-                <GenericPropertyTabComponent globalState={this.props.globalState} guiControl={this.props.guiControl}/>
-            </>
-        );
-    }
-}
-
-export class GeneralPropertyTabComponent extends React.Component<IPropertyComponentProps> {
-    constructor(props: IPropertyComponentProps) {
-        super(props);
-    }
-
-    render() {
-        return (
-            <>
-                <LineContainerComponent title="GENERAL">
-                </LineContainerComponent>
-            </>
-        );
-    }
-}
-
-export class GenericPropertyTabComponent extends React.Component<IPropertyComponentProps> {
-    constructor(props: IPropertyComponentProps) {
-        super(props);
-    }
-
-    forceRebuild(notifiers?: { "rebuild"?: boolean; "update"?: boolean; }) {
-        if (!notifiers || notifiers.update) {
-            this.props.globalState.onUpdateRequiredObservable.notifyObservers();
-        }
-
-        if (!notifiers || notifiers.rebuild) {
-            this.props.globalState.onRebuildRequiredObservable.notifyObservers();
-        }
-    }
-
-    render() {
-        const block = this.props.guiControl,
-              propStore: IPropertyDescriptionForEdition[] = (block as any)._propStore;
-
-        if (!propStore) {
-            return (
-                <>
-                </>
-            );
-        }
-
-        const componentList: { [groupName: string]: JSX.Element[]} = {},
-              groups: string[] = [];
-
-        for (const { propertyName, displayName, type, groupName, options } of propStore) {
-            let components = componentList[groupName];
-
-            if (!components) {
-                components = [];
-                componentList[groupName] = components;
-                groups.push(groupName);
-            }
-
-            switch (type) {
-                case PropertyTypeForEdition.Boolean: {
-                    components.push(
-                        <CheckBoxLineComponent label={displayName} target={this.props.guiControl} propertyName={propertyName} onValueChanged={() => this.forceRebuild(options.notifiers)} />
-                    );
-                    break;
-                }
-                case PropertyTypeForEdition.Float: {
-                    let cantDisplaySlider = (isNaN(options.min as number) || isNaN(options.max as number) || options.min === options.max);
-                    if (cantDisplaySlider) {
-                        components.push(
-                            <FloatLineComponent globalState={this.props.globalState} label={displayName} propertyName={propertyName} target={this.props.guiControl} onChange={() => this.forceRebuild(options.notifiers)} />
-                        );
-                    } else {
-                        components.push(
-                            <SliderLineComponent label={displayName} target={this.props.guiControl} globalState={this.props.globalState} propertyName={propertyName} step={Math.abs((options.max as number) - (options.min as number)) / 100.0} minimum={Math.min(options.min as number, options.max as number)} maximum={options.max as number} onChange={() => this.forceRebuild(options.notifiers)}/>
-                        );
-                    }
-                    break;
-                }
-            }
-        }
-
-        return (
-            <>
-            {
-                groups.map((group) =>
-                    <LineContainerComponent title={group}>
-                        {componentList[group]}
-                    </LineContainerComponent>
-                )
-            }
-            </>
-        );
-    }
-}

+ 0 - 7
guiEditor/src/diagram/properties/propertyComponentProps.ts

@@ -1,7 +0,0 @@
-import { Control } from "babylonjs-gui/2D/controls/control";
-import { GlobalState } from "../../globalState";
-
-export interface IPropertyComponentProps {
-    globalState: GlobalState;
-    guiControl: Control;
-}

+ 31 - 3
guiEditor/src/diagram/workbench.tsx

@@ -150,7 +150,7 @@ export class WorkbenchComponent extends React.Component<IWorkbenchComponentProps
                 this._selectedGuiNodes = [];
             } 
             else {
-                if (selection instanceof GUINode){
+                if (selection instanceof GUINode ) {
                     if (this._ctrlKeyIsPressed) {
                         if (this._selectedGuiNodes.indexOf(selection) === -1) {
                             this._selectedGuiNodes.push(selection);
@@ -159,6 +159,7 @@ export class WorkbenchComponent extends React.Component<IWorkbenchComponentProps
                     else {              
                         this._selectedGuiNodes = [selection];
                     }
+                    
                 
                 } 
             }
@@ -194,7 +195,7 @@ export class WorkbenchComponent extends React.Component<IWorkbenchComponentProps
         }
 		return gridSize * Math.floor(position / gridSize);
     }
-    
+
     public getGridPositionCeil(position: number) {
         let gridSize = this.gridSize;
 		if (gridSize === 0) {
@@ -203,6 +204,29 @@ export class WorkbenchComponent extends React.Component<IWorkbenchComponentProps
 		return gridSize * Math.ceil(position / gridSize);
 	}
 
+    loadFromJson(serializationObject: any) {
+        this.globalState.onSelectionChangedObservable.notifyObservers(null);
+        this._guiNodes = [];
+        this.globalState.guiTexture.parseContent(serializationObject);
+        this.props.globalState.workbench.loadFromGuiTexture();
+    }
+    
+    async loadFromSnippet(snippedID: string){
+        this.globalState.onSelectionChangedObservable.notifyObservers(null);
+        this._guiNodes = [];
+        await this.globalState.guiTexture.parseFromSnippetAsync(snippedID);
+        this.props.globalState.workbench.loadFromGuiTexture();
+    }
+    
+    loadFromGuiTexture()
+    {
+        var children = this.globalState.guiTexture.getChildren();
+        children[0].children.forEach(guiElement => {
+            var newGuiNode = new GUINode(this.props.globalState, guiElement);
+            this._guiNodes.push(newGuiNode);
+        });
+    }
+
     updateTransform() {
         this._rootContainer.style.transform = `translate(${this._x}px, ${this._y}px) scale(${this._zoom})`;
 
@@ -399,9 +423,11 @@ export class WorkbenchComponent extends React.Component<IWorkbenchComponentProps
         }
         
         this._mouseStartPointX = evt.clientX;
-        this._mouseStartPointY = evt.clientY;        
+        this._mouseStartPointY = evt.clientY;   
+             
     }
 
+    public isUp : boolean = true;
     onUp(evt: React.PointerEvent) {
         this._mouseStartPointX = null;
         this._mouseStartPointY = null;
@@ -420,6 +446,8 @@ export class WorkbenchComponent extends React.Component<IWorkbenchComponentProps
             this._frameCandidate = null;
 
         }
+        this.isUp = true;
+        
     }
 
     onWheel(evt: React.WheelEvent) {

+ 1 - 2
guiEditor/src/guiEditor.ts

@@ -3,7 +3,6 @@ import * as ReactDOM from "react-dom";
 import { GlobalState } from "./globalState";
 import { WorkbenchEditor } from "./workbenchEditor";
 import { Popup } from "./sharedUiComponents/lines/popup";
-import { SerializationTools } from "./serializationTools";
 import { Observable } from "babylonjs/Misc/observable";
 /**
  * Interface used to specify creation options for the gui editor
@@ -57,7 +56,7 @@ export class GUIEditor {
 
         if (options.customLoadObservable) {
             options.customLoadObservable.add((data) => {
-                SerializationTools.Deserialize(data, globalState);
+                //TODO: Add deserilization here.
                 globalState.onResetRequiredObservable.notifyObservers();
                 globalState.onBuiltObservable.notifyObservers();
             });

+ 0 - 8
guiEditor/src/serializationTools.ts

@@ -1,8 +0,0 @@
-import { GlobalState } from './globalState';
-
-export class SerializationTools {
-
-    public static Deserialize(serializationObject: any, globalState: GlobalState) {
-        globalState.onIsLoadingChanged.notifyObservers(true);
-    }
-}

+ 1 - 1
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -4,7 +4,7 @@ import { GlobalState } from '../../globalState';
 import { Nullable } from 'babylonjs/types';
 import { ButtonLineComponent } from '../../sharedComponents/buttonLineComponent';
 import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
-import { StringTools } from '../../stringTools';
+import { StringTools } from '../../sharedUiComponents/stringTools';
 import { FileButtonLineComponent } from '../../sharedComponents/fileButtonLineComponent';
 import { Tools } from 'babylonjs/Misc/tools';
 import { SerializationTools } from '../../serializationTools';

+ 6 - 3
nodeEditor/src/diagram/display/inputDisplayManager.ts

@@ -7,7 +7,6 @@ import { AnimatedInputBlockTypes } from 'babylonjs/Materials/Node/Blocks/Input/a
 import { Vector2, Vector3, Vector4 } from 'babylonjs/Maths/math.vector';
 import { Color3 } from 'babylonjs/Maths/math.color';
 import { BlockTools } from '../../blockTools';
-import { StringTools } from '../../stringTools';
 
 const inputNameToAttributeValue: { [name: string] : string } = {
     "position2d" : "position",
@@ -46,15 +45,19 @@ export class InputDisplayManager implements IDisplayManager {
 
     public getHeaderText(block: NodeMaterialBlock): string {
         let inputBlock = block as InputBlock;
-        let name = `${inputBlock.name} (${StringTools.GetBaseType(inputBlock.output.type)})`;
+        let name = `${inputBlock.name} (${InputDisplayManager.GetBaseType(inputBlock.output.type)})`;
 
         if (inputBlock.isAttribute) {
-            name = StringTools.GetBaseType(inputBlock.output.type);
+            name = InputDisplayManager.GetBaseType(inputBlock.output.type);
         }
 
         return name;
     }
 
+    public static GetBaseType(type: NodeMaterialBlockConnectionPointTypes): string {
+        return NodeMaterialBlockConnectionPointTypes[type];
+    }
+
     public getBackgroundColor(block: NodeMaterialBlock): string {
         let color = "";
         let inputBlock = block as InputBlock;

+ 1 - 1
nodeEditor/src/diagram/graphFrame.ts

@@ -7,7 +7,7 @@ import { IFrameData } from '../nodeLocationInfo';
 import { Color3 } from 'babylonjs/Maths/math.color';
 import { NodePort } from './nodePort';
 import { SerializationTools } from '../serializationTools';
-import { StringTools } from '../stringTools';
+import { StringTools } from '../sharedUiComponents/stringTools';
 import { FrameNodePort } from './frameNodePort';
 
 enum ResizingDirection {

+ 0 - 10
nodeEditor/src/stringTools.ts

@@ -1,5 +1,3 @@
-import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/Enums/nodeMaterialBlockConnectionPointTypes';
-
 export class StringTools {
     /*
      * Based on FileSaver.js
@@ -75,14 +73,6 @@ export class StringTools {
     }
 
     /**
-     * Gets the base math type of node material block connection point.
-     * @param type Type to parse.
-     */
-    public static GetBaseType(type: NodeMaterialBlockConnectionPointTypes): string {
-        return NodeMaterialBlockConnectionPointTypes[type];
-    }
-
-    /**
      * Download a string into a file that will be saved locally by the browser
      * @param content defines the string to download locally as a file
      */