Browse Source

Merge pull request #1110 from AtomicGameEngine/JME-ATOMIC-1108

Restoring ability to load examples directly from AtomicExamples repo
JoshEngebretson 9 years ago
parent
commit
944d96002f
36 changed files with 291 additions and 279 deletions
  1. BIN
      Data/AtomicEditor/ExampleInfo/AtomicBlaster.png
  2. BIN
      Data/AtomicEditor/ExampleInfo/AtomicMutant.png
  3. BIN
      Data/AtomicEditor/ExampleInfo/Basic2D.png
  4. BIN
      Data/AtomicEditor/ExampleInfo/Basic3D.png
  5. BIN
      Data/AtomicEditor/ExampleInfo/Breakout.png
  6. BIN
      Data/AtomicEditor/ExampleInfo/BunnyMark.png
  7. BIN
      Data/AtomicEditor/ExampleInfo/Butterflies.png
  8. BIN
      Data/AtomicEditor/ExampleInfo/CharacterAnimation2D.png
  9. BIN
      Data/AtomicEditor/ExampleInfo/CharacterAnimation3D.png
  10. BIN
      Data/AtomicEditor/ExampleInfo/Chickens.png
  11. BIN
      Data/AtomicEditor/ExampleInfo/CubeMapExample.png
  12. BIN
      Data/AtomicEditor/ExampleInfo/EventLoop.png
  13. 25 159
      Data/AtomicEditor/ExampleInfo/Examples.json
  14. BIN
      Data/AtomicEditor/ExampleInfo/Light2D.png
  15. BIN
      Data/AtomicEditor/ExampleInfo/ParticleEmitter3D.png
  16. BIN
      Data/AtomicEditor/ExampleInfo/Particles2D.png
  17. BIN
      Data/AtomicEditor/ExampleInfo/PhysicsPlatformer2D.png
  18. BIN
      Data/AtomicEditor/ExampleInfo/RenderToTexture.png
  19. BIN
      Data/AtomicEditor/ExampleInfo/Roboman3D.png
  20. BIN
      Data/AtomicEditor/ExampleInfo/SpaceGame.png
  21. BIN
      Data/AtomicEditor/ExampleInfo/ToonTown.png
  22. BIN
      Data/AtomicEditor/ExampleInfo/UIExample.png
  23. BIN
      Data/AtomicEditor/ExampleInfo/UISceneView2D.png
  24. BIN
      Data/AtomicEditor/ExampleInfo/UIWebView.png
  25. BIN
      Data/AtomicEditor/ExampleInfo/WaterShip.png
  26. BIN
      Data/AtomicEditor/ExampleInfo/WebTexture3D.png
  27. BIN
      Data/AtomicEditor/ExampleInfo/WebView3D.png
  28. 8 0
      Script/AtomicEditor/editor/EditorEvents.ts
  29. 53 12
      Script/AtomicEditor/resources/ProjectTemplates.ts
  30. 67 0
      Script/AtomicEditor/resources/ResourceOps.ts
  31. 2 3
      Script/AtomicEditor/ui/frames/WelcomeFrame.ts
  32. 3 3
      Script/AtomicEditor/ui/frames/menus/MainFrameMenu.ts
  33. 118 100
      Script/AtomicEditor/ui/modal/CreateProject.ts
  34. 2 2
      Script/AtomicEditor/ui/modal/ModalOps.ts
  35. 1 0
      Script/TypeScript/AtomicWork.d.ts
  36. 12 0
      Source/AtomicJS/Javascript/JSFileSystem.cpp

BIN
Data/AtomicEditor/ExampleInfo/AtomicBlaster.png


BIN
Data/AtomicEditor/ExampleInfo/AtomicMutant.png


BIN
Data/AtomicEditor/ExampleInfo/Basic2D.png


BIN
Data/AtomicEditor/ExampleInfo/Basic3D.png


BIN
Data/AtomicEditor/ExampleInfo/Breakout.png


BIN
Data/AtomicEditor/ExampleInfo/BunnyMark.png


BIN
Data/AtomicEditor/ExampleInfo/Butterflies.png


BIN
Data/AtomicEditor/ExampleInfo/CharacterAnimation2D.png


BIN
Data/AtomicEditor/ExampleInfo/CharacterAnimation3D.png


BIN
Data/AtomicEditor/ExampleInfo/Chickens.png


BIN
Data/AtomicEditor/ExampleInfo/CubeMapExample.png


BIN
Data/AtomicEditor/ExampleInfo/EventLoop.png


+ 25 - 159
Data/AtomicEditor/ExampleInfo/Examples.json

@@ -1,163 +1,29 @@
 {
     "examples" : [
-
-        {
-            "name": "Feature Examples",
-            "desc" : "Multiple Feature Examples",
-            "screenshot" : "Example.png",
-            "folder" : "FeatureExamples"
-        },
-        {
-            "name": "Basic2D",
-            "desc" : "Basic2D Scene Example",
-            "screenshot" : "Basic2D.png",
-            "folder" : "Basic2D"
-        },
-        {
-            "name": "Basic3D",
-            "desc" : "Basic3D Scene Example",
-            "screenshot" : "Basic3D.png",
-            "folder" : "Basic3D"
-        },
-        {
-            "name": "2D Physics Platformer",
-            "desc" : "Moving platforms, vines, bats, oh my!",
-            "screenshot" : "PhysicsPlatformer2D.png",
-            "folder" : "PhysicsPlatformer"
-        },
-        {
-            "name": "ToonTown",
-            "desc" : "A cartoony scene with 3D character and physics",
-            "screenshot" : "ToonTown.png",
-            "folder" : "ToonTown"
-        },
-        {
-            "name": "AtomicBlaster",
-            "desc" : "Port of ShapeBlaster for XNA by Michael Hoffman",
-            "screenshot" : "AtomicBlaster.png",
-            "namespace" : "AtomicBlaster",
-            "appDelegateClass" : "GameRoot",
-            "folder" : "AtomicBlaster"
-        },
-        {
-            "name": "Roboman3D",
-            "desc" : "Character Controller with Physics",
-            "screenshot" : "Roboman3D.png",
-            "folder" : "RoboMan3D"
-        },
-        {
-            "name": "AtomicMutant",
-            "desc" : "Character Controller with Physics",
-            "screenshot" : "AtomicMutant.png",
-            "folder" : "AtomicMutant"
-        },
-        {
-            "name": "Butterflies",
-            "desc" : "Beautiful Butterflies!",
-            "screenshot" : "Butterflies.png",
-            "folder" : "Butterflies"
-        },
-        {
-            "name": "Space Game",
-            "desc" : "Example of simple game loop, UI, post process effects",
-            "screenshot" : "SpaceGame.png",
-            "folder" : "SpaceGame"
-        },
-        {
-            "name": "UIWebView",
-            "desc" : "Example Chromium WebView Widget",
-            "screenshot" : "UIWebView.png",
-            "folder" : "AtomicWebView"
-        },
-        {
-            "name": "WebView3D",
-            "desc" : "Example rendering a Chromium WebView in a 3D scene",
-            "screenshot" : "WebView3D.png",
-            "folder" : "WebView3D"
-        },
-        {
-            "name": "ParticleEmitter3D",
-            "desc" : "3D Particle Emitters",
-            "screenshot" : "ParticleEmitter3D.png",
-            "folder" : "ParticleEmitter3D"
-        },
-        {
-            "name": "Particles2D",
-            "desc" : "2D Particle Emitters",
-            "screenshot" : "Particles2D.png",
-            "folder" : "Particles2D"
-        },
-        {
-            "name": "Physics2D",
-            "desc" : "Simple 2D physics example",
-            "screenshot" : "Example.png",
-            "folder" : "Physics2D"
-        },
-        {
-            "name": "Breakout",
-            "desc" : "Simple version of the arcade classic",
-            "screenshot" : "Breakout.png",
-            "folder" : "Breakout"
-        },
-        {
-            "name": "CharacterAnimation2D",
-            "desc" : "2D Character Animation using Spriter",
-            "screenshot" : "CharacterAnimation2D.png",
-            "folder" : "CharacterAnimation2D"
-        },
-        {
-            "name": "CharacterAnimation3D",
-            "desc" : "3D Character Controller example",
-            "screenshot" : "CharacterAnimation3D.png",
-            "folder" : "CharacterAnimation3D"
-        },
-        {
-            "name": "Chickens",
-            "desc" : "Animated chickens, wandering about, cluck!",
-            "screenshot" : "Chickens.png",
-            "folder" : "Chickens"
-        },
-        {
-            "name": "CubeMapExample",
-            "desc" : "Cubemap rendering and generator example",
-            "screenshot" : "CubeMapExample.png",
-            "folder" : "CubeMapExample"
-        },
-        {
-            "name": "Light2D",
-            "desc" : "2D Lighting with shadows",
-            "screenshot" : "Light2D.png",
-            "folder" : "Light2DExample"
-        },
-        {
-            "name": "Render to Texture",
-            "desc" : "Example of rendering a scene on a 3d object",
-            "screenshot" : "RenderToTexture.png",
-            "folder" : "RenderToTexture"
-        },
-        {
-            "name": "Multiplayer Space Game",
-            "desc" : "Space Game varient with master server and NAT punchthru",
-            "screenshot" : "SpaceGame.png",
-            "folder" : "SpaceGameMultiplayer"
-        },
-        {
-            "name": "UISceneView2D",
-            "desc" : "Example of rendering a scene to a UISceneView widget",
-            "screenshot" : "UISceneView2D.png",
-            "folder" : "UISceneView2D"
-        },
-        {
-            "name": "WebTexture3D",
-            "desc" : "Example rendering a Chromium WebView on a 3D surface",
-            "screenshot" : "WebTexture3D.png",
-            "folder" : "WebTexture"
-        },
-        {
-            "name": "WaterShip",
-            "desc" : "Example water shader",
-            "screenshot" : "WaterShip.png",
-            "folder" : "WaterShip"
-        }
+        "FeatureExamples",
+        "Basic2D",
+        "Basic3D",
+        "PhysicsPlatformer",
+        "ToonTown",
+        "AtomicBlaster",
+        "RoboMan3D",
+        "AtomicMutant",
+        "Butterflies",
+        "SpaceGame",
+        "AtomicWebView",
+        "WebView3D",
+        "ParticleEmitter3D",
+        "Particles2D",
+        "Physics2D",
+        "Breakout",
+        "CharacterAnimation2D",
+        "CharacterAnimation3D",
+        "Chickens",
+        "CubeMapExample",
+        "Light2DExample",
+        "RenderToTexture",
+        "UISceneView2D",
+        "WebTexture",
+        "WaterShip"
     ]
 }

BIN
Data/AtomicEditor/ExampleInfo/Light2D.png


BIN
Data/AtomicEditor/ExampleInfo/ParticleEmitter3D.png


BIN
Data/AtomicEditor/ExampleInfo/Particles2D.png


BIN
Data/AtomicEditor/ExampleInfo/PhysicsPlatformer2D.png


BIN
Data/AtomicEditor/ExampleInfo/RenderToTexture.png


BIN
Data/AtomicEditor/ExampleInfo/Roboman3D.png


BIN
Data/AtomicEditor/ExampleInfo/SpaceGame.png


BIN
Data/AtomicEditor/ExampleInfo/ToonTown.png


BIN
Data/AtomicEditor/ExampleInfo/UIExample.png


BIN
Data/AtomicEditor/ExampleInfo/UISceneView2D.png


BIN
Data/AtomicEditor/ExampleInfo/UIWebView.png


BIN
Data/AtomicEditor/ExampleInfo/WaterShip.png


BIN
Data/AtomicEditor/ExampleInfo/WebTexture3D.png


BIN
Data/AtomicEditor/ExampleInfo/WebView3D.png


+ 8 - 0
Script/AtomicEditor/editor/EditorEvents.ts

@@ -68,6 +68,14 @@ export const CloseProject = "EditorCloseProject";
 export const ProjectClosed = "EditorProjectClosed";
 export const ProjectUnloadedNotification = "ProjectUnloadedNotification";
 
+export const RequestProjectLoad = "RequestProjectLoad";
+export interface RequestProjectLoadEvent {
+
+  // The full path to the .atomic file
+  path: string;
+
+}
+
 export const LoadProject = "EditorLoadProject";
 export const LoadProjectNotification = "EditorLoadProjectNotification";
 export interface LoadProjectEvent {

+ 53 - 12
Script/AtomicEditor/resources/ProjectTemplates.ts

@@ -31,7 +31,7 @@ export interface ProjectTemplateDefinition {
     folder: string;
     languages: string[];
     appDelegateClass: string;
-    namespace: string[];
+    namespace: string;
 }
 
 // Supported project languages
@@ -96,29 +96,70 @@ export function getExampleProjectTemplateDefinitions(): [ProjectTemplateDefiniti
         return;
     }
 
-    let exampleJson = JSON.parse(jsonFile.readText());
-    let examples = <[ProjectTemplateDefinition]>exampleJson.examples;
+    let exampleFoldersJson = JSON.parse(jsonFile.readText());
+
+    // list of example folders
+    let exampleFolders = <[string]>exampleFoldersJson.examples;
+
+    let examples = <[ProjectTemplateDefinition]>[];
 
     // Update all the paths to a more fully qualified path
-    examples.forEach(example => {
+    exampleFolders.forEach(exampleFolder => {
 
-        example.folder = env.toolDataDir + "AtomicExamples/" + example.folder + "/";
+        let folder = Atomic.addTrailingSlash(env.toolDataDir + "AtomicExamples/" + exampleFolder);
+        let screenshot = folder + "Screenshot.png";
 
-        example.languages = [];
+        if (!fileSystem.dirExists(folder)) {
+            console.log("Skipping non-existent example ", folder);
+            return;
+        }
 
-        for (var i = 0; i < projectLanguages.length; i++) {
+        let exampleJsonFilename = folder + "AtomicExample.json";
 
-            if (fileSystem.dirExists(example.folder + projectLanguages[i])) {
-                example.languages.push(projectLanguages[i]);
+        if (!fileSystem.fileExists(exampleJsonFilename)) {
+            console.log("Skipping non-existent example json", exampleJsonFilename);
+            return;
+        }
+
+        jsonFile = new Atomic.File(exampleJsonFilename, Atomic.FILE_READ);
+
+        if (!jsonFile.isOpen()) {
+            console.log("Unable to open example json", exampleJsonFilename);
+            return;
+        }
+
+
+        let exampleJson = JSON.parse(jsonFile.readText());
+
+        if (!exampleJson.name || !exampleJson.desc) {
+            console.log("Unable to parse example json", exampleJsonFilename);
+            return;
+        }
+
+        let allLanguages = ["CSharp", "JavaScript", "TypeScript"];
+        let languages = [];
+
+        for (var i = 0; i < allLanguages.length; i++) {
+
+            if (fileSystem.dirExists(folder + allLanguages[i])) {
+                languages.push(allLanguages[i]);
             }
 
         }
 
-        example.screenshot = exampleInfoDir + example.screenshot;
+        examples.push({
+            name : exampleJson.name,
+            desc : exampleJson.desc,
+            screenshot : screenshot,
+            folder : folder,
+            languages : languages,
+            appDelegateClass : exampleJson.appDelegateClass,
+            namespace : exampleJson.namespace
+        })
 
     });
 
-    return exampleJson.examples;
+    return examples;
 }
 
 /**
@@ -335,7 +376,7 @@ function generateAtomicNETDesktopProject():boolean {
     if (!processAtomicNETTemplate(desktopFolder + "Program.cs", templateFolder + "Platforms/Desktop/Program.cs")) {
         return false;
     }
-    
+
     return true;
 }
 

+ 67 - 0
Script/AtomicEditor/resources/ResourceOps.ts

@@ -21,6 +21,8 @@
 //
 
 import EditorEvents = require("../editor/EditorEvents");
+import EditorUI = require("../ui/EditorUI");
+import ProjectTemplates = require("ProjectTemplates");
 
 class ResourceOps extends Atomic.ScriptObject {
 
@@ -34,8 +36,73 @@ class ResourceOps extends Atomic.ScriptObject {
 
         });
 
+        this.subscribeToEvent(EditorEvents.RequestProjectLoad, (ev: EditorEvents.RequestProjectLoadEvent) => { this.handleRequestProjectLoad(ev); })
+
     }
 
+    handleRequestProjectLoad(ev:EditorEvents.RequestProjectLoadEvent) {
+
+        var fs = Atomic.fileSystem;
+        var projectPath = Atomic.addTrailingSlash(Atomic.getPath(ev.path));
+
+        var openProject = () => this.sendEvent(EditorEvents.LoadProject, { path: ev.path });
+
+        // Check whether there is a cache folder, if so, this project has been loaded before
+        if (Atomic.fileSystem.dirExists(projectPath + "Cache")) {
+            openProject();
+            return;
+        } else {
+
+            // this may be an example
+            var parentPath = Atomic.getParentPath(projectPath);
+            var exampleInfoPath = parentPath + "AtomicExample.json";
+
+            if (!fs.fileExists(exampleInfoPath)) {
+
+                openProject();
+                return;
+            }
+
+            var jsonFile = new Atomic.File(exampleInfoPath, Atomic.FILE_READ);
+
+            if (!jsonFile.isOpen()) {
+                return;
+            }
+
+            var exampleJson = JSON.parse(jsonFile.readText());
+
+            var allLanguages = ["CSharp", "JavaScript", "TypeScript"];
+            var language = null;
+
+            for (var i = 0; i < allLanguages.length; i++) {
+
+                if (projectPath.indexOf(allLanguages[i]) != -1) {
+                    language = allLanguages[i];
+                    break
+                }
+            }
+
+            if (!language) {
+                return;
+            }
+
+            var projectDef = {
+                name : exampleJson.name ? exampleJson.name : "Anonymous Example",
+                desc : exampleJson.desc ? exampleJson.desc : "",
+                screenshot : parentPath + "Screenshot.png",
+                folder : parentPath,
+                languages : [language],
+                appDelegateClass : exampleJson.appDelegateClass,
+                namespace : exampleJson.namespace
+
+            }
+
+            var ops = EditorUI.getModelOps();
+            ops.showCreateProject(projectDef, projectPath);
+
+        }
+
+    }
 
 }
 

+ 2 - 3
Script/AtomicEditor/ui/frames/WelcomeFrame.ts

@@ -69,7 +69,6 @@ class WelcomeFrame extends ScriptWidget {
     handleClickedExample(example: ProjectTemplates.ProjectTemplateDefinition) {
 
         var ops = EditorUI.getModelOps();
-        var env = ToolCore.toolEnvironment;
         ops.showCreateProject(example);
     }
 
@@ -234,7 +233,7 @@ class WelcomeFrame extends ScriptWidget {
                 var path = utils.openProjectFileDialog();
                 if (path) {
 
-                    this.sendEvent(EditorEvents.LoadProject, { path: path });
+                    this.sendEvent(EditorEvents.RequestProjectLoad, { path: path });
 
                 }
 
@@ -254,7 +253,7 @@ class WelcomeFrame extends ScriptWidget {
                     return;
                 }
                 var path: string = this.recent[this.recentList.getSelectedItemID()];
-                this.sendEvent(EditorEvents.LoadProject, { path: path });
+                this.sendEvent(EditorEvents.RequestProjectLoad, { path: path });
             }
 
             if (id == "recentProjectsContextMenu") {

+ 3 - 3
Script/AtomicEditor/ui/frames/menus/MainFrameMenu.ts

@@ -171,14 +171,14 @@ class MainFrameMenu extends Atomic.ScriptObject {
 
                 }
 
-                var openProject = () => this.sendEvent(EditorEvents.LoadProject, { path: path });
+                var requestProjectLoad = () => this.sendEvent(EditorEvents.RequestProjectLoad, { path: path });
 
                 if (ToolCore.toolSystem.project) {
 
                     this.subscribeToEvent(EditorEvents.ProjectClosed, () => {
 
                         this.unsubscribeFromEvent(EditorEvents.ProjectClosed);
-                        openProject();
+                        requestProjectLoad();
 
                     });
 
@@ -186,7 +186,7 @@ class MainFrameMenu extends Atomic.ScriptObject {
 
                 } else {
 
-                    openProject();
+                    requestProjectLoad();
 
                 }
 

+ 118 - 100
Script/AtomicEditor/ui/modal/CreateProject.ts

@@ -28,10 +28,11 @@ import ProjectTemplates = require("../../resources/ProjectTemplates");
 
 class CreateProject extends ModalWindow {
 
-    constructor(projectTemplate: ProjectTemplates.ProjectTemplateDefinition) {
+    constructor(projectTemplate: ProjectTemplates.ProjectTemplateDefinition, projectPath?: string) {
 
         super();
 
+        this.projectPath = projectPath;
         this.projectTemplate = projectTemplate;
 
         this.init("Create Project", "AtomicEditor/editor/ui/createproject.tb.txt");
@@ -67,7 +68,13 @@ class CreateProject extends ModalWindow {
 
         }
 
-        this.projectPathField.text = userDocuments;
+        // If we're specifying where to put the project (initially), then we are opening
+        // an example directly so use the same name
+        if (projectPath) {
+            this.projectNameField.text = projectTemplate.name;
+        }
+
+        this.projectPathField.text = projectPath ? projectPath : userDocuments;
         this.populateLanguageSelectionList();
 
         // Need to manually set the focus so the contents get auto-selected
@@ -133,144 +140,153 @@ class CreateProject extends ModalWindow {
 
         var folder = this.projectPathField.text.trim();
 
+        var projectPath = this.projectPath;
+
+        // if we changed the project path, clear it
+        if (folder != this.projectPath) {
+            projectPath = "";
+        }
+
         if (!folder) {
             EditorUI.showModalError("New Project Editor Error", "Please choose a root project folder");
             return false;
         }
 
-        folder += "/" + name;
-
         var fileSystem = Atomic.getFileSystem();
 
-        if (fileSystem.dirExists(folder) || fileSystem.fileExists(folder)) {
+        if (!projectPath) {
 
-            var message = folder + " exists\n\nPlease choose a different root folder or project name";
-            EditorUI.showModalError("New Project Editor Error", message);
-            return false;
+            folder += "/" + name;
+
+            if (fileSystem.dirExists(folder) || fileSystem.fileExists(folder)) {
 
+                var message = folder + " exists\n\nPlease choose a different root folder or project name";
+                EditorUI.showModalError("New Project Editor Error", message);
+                return false;
+
+            }
         }
 
         folder = Atomic.addTrailingSlash(folder);
-        if (!fileSystem.dirExists(folder)) {
 
-            // Determine if we have a language template for the selected language.
-            let selectedLanguage = this.projectLanguageField.text;
+        // Determine if we have a language template for the selected language.
+        let selectedLanguage = this.projectLanguageField.text;
 
-            // Check whether we have a required IDE installed for C# projects
-            var atomicNET = false;
-            if (selectedLanguage == "CSharp" || selectedLanguage == "C#") {
+        // Check whether we have a required IDE installed for C# projects
+        var atomicNET = false;
+        if (selectedLanguage == "CSharp" || selectedLanguage == "C#") {
 
-                atomicNET = true;
-                if (!ToolCore.netProjectSystem.getIDEAvailable()) {
-                    this.hide();
-                    EditorUI.getModelOps().showAtomicNETWindow();
-                    return false;
-                }
+            atomicNET = true;
+            if (!ToolCore.netProjectSystem.getIDEAvailable()) {
+                this.hide();
+                EditorUI.getModelOps().showAtomicNETWindow();
+                return false;
             }
+        }
 
-            let templateFolder = "";
-            for (let i = 0; i < this.projectTemplate.languages.length; i++) {
-                if (this.projectTemplate.languages[i] === selectedLanguage) {
-                    templateFolder = this.projectTemplate.folder + selectedLanguage + "/";
-                    break;
-                }
+        let templateFolder = "";
+        for (let i = 0; i < this.projectTemplate.languages.length; i++) {
+            if (this.projectTemplate.languages[i] === selectedLanguage) {
+                templateFolder = this.projectTemplate.folder + selectedLanguage + "/";
+                break;
             }
+        }
 
-            // Do the creation!
-            if (templateFolder != "" && fileSystem.dirExists(templateFolder)) {
+        // Do the creation!
+        if (templateFolder != "" && fileSystem.dirExists(templateFolder)) {
 
+            if (!projectPath) {
                 if (!fileSystem.copyDir(templateFolder, folder)) {
-                  var message = "Unable to copy folder: " + templateFolder + " to " + folder;
-                  EditorUI.showModalError("New Project Editor Error", message);
-                  return false;
+                    var message = "Unable to copy folder: " + templateFolder + " to " + folder;
+                    EditorUI.showModalError("New Project Editor Error", message);
+                    return false;
                 }
+            }
 
-                var utils = new Editor.FileUtils();
+            var utils = new Editor.FileUtils();
 
-                utils.createDirs(folder + "Cache");
-                utils.createDirs(folder + "Settings");
+            utils.createDirs(folder + "Cache");
+            utils.createDirs(folder + "Settings");
 
-                if (!fileSystem.dirExists(folder)) {
-                    var message = "Unable to create folder: " + folder + "\n\nPlease choose a different root folder or project name";
-                    EditorUI.showModalError("New Project Editor Error", message);
-                    return false;
-                }
+            if (!fileSystem.dirExists(folder)) {
+                var message = "Unable to create folder: " + folder + "\n\nPlease choose a different root folder or project name";
+                EditorUI.showModalError("New Project Editor Error", message);
+                return false;
+            }
 
-                // Look for the .atomic project file and if it exists, then rename it
-                let fileResults = fileSystem.scanDir(folder, "*.atomic", Atomic.SCAN_FILES, false);
-                if (fileResults.length === 1) {
-                    fileSystem.rename(folder + fileResults[0], folder + name + ".atomic");
-                } else {
-                    // Just create the file.  We either don't have one existing, or we have more than one and don't know which one to rename
-                    var file = new Atomic.File(folder + name + ".atomic", Atomic.FILE_WRITE);
-                    file.close();
-                }
+            // Look for the .atomic project file and if it exists, then rename it
+            let fileResults = fileSystem.scanDir(folder, "*.atomic", Atomic.SCAN_FILES, false);
+            if (fileResults.length === 1) {
+                fileSystem.rename(folder + fileResults[0], folder + name + ".atomic");
+            } else {
+                // Just create the file.  We either don't have one existing, or we have more than one and don't know which one to rename
+                var file = new Atomic.File(folder + name + ".atomic", Atomic.FILE_WRITE);
+                file.close();
+            }
 
-                // Look for a .userprefs file and if it exists, then rename it
-                fileResults = fileSystem.scanDir(folder, "*.userprefs", Atomic.SCAN_FILES, false);
-                if (fileResults.length === 1) {
-                    fileSystem.rename(folder + fileResults[0], folder + name + ".userprefs");
-                }
+            // Look for a .userprefs file and if it exists, then rename it
+            fileResults = fileSystem.scanDir(folder, "*.userprefs", Atomic.SCAN_FILES, false);
+            if (fileResults.length === 1) {
+                fileSystem.rename(folder + fileResults[0], folder + name + ".userprefs");
+            }
 
-                // create project settings
+            // create project settings
 
-                var platforms = ["desktop"];
+            var platforms = ["desktop"];
 
-                if (this.androidButton.value == 1) {
-                    platforms.push("android");
-                }
+            if (this.androidButton.value == 1) {
+                platforms.push("android");
+            }
 
-                if (this.iosButton.value == 1) {
-                    platforms.push("ios");
-                }
+            if (this.iosButton.value == 1) {
+                platforms.push("ios");
+            }
 
-                var projectSettings = {
-                    name : name,
-                    platforms : platforms
-                }
+            var projectSettings = {
+                name : name,
+                platforms : platforms
+            }
 
-                var jsonFile = new Atomic.File(folder + "Settings/Project.json", Atomic.FILE_WRITE);
-                if (jsonFile.isOpen()) {
-                    jsonFile.writeString(JSON.stringify(projectSettings, null, 2));
-                    jsonFile.flush();
-                    jsonFile.close();
-                }
+            var jsonFile = new Atomic.File(folder + "Settings/Project.json", Atomic.FILE_WRITE);
+            if (jsonFile.isOpen()) {
+                jsonFile.writeString(JSON.stringify(projectSettings, null, 2));
+                jsonFile.flush();
+                jsonFile.close();
+            }
 
-                // Generate AtomicNET project if necessary
-                if (atomicNET) {
-                    if (!ProjectTemplates.generateAtomicNETProject({
-                        name: name,
-                        appID : this.appIDField.text,
-                        platforms : platforms,
-                        projectFolder : folder,
-                        projectTemplate : this.projectTemplate
-                    })) {
-                        var message = "Unable to generate AtomicNET project: " + folder;
-                        EditorUI.showModalError("New Project Editor Error", message);
-                        return false;
-                    }
+            // Generate AtomicNET project if necessary
+            if (atomicNET) {
+                if (!ProjectTemplates.generateAtomicNETProject({
+                    name: name,
+                    appID : this.appIDField.text,
+                    platforms : platforms,
+                    projectFolder : folder,
+                    projectTemplate : this.projectTemplate
+                })) {
+                    var message = "Unable to generate AtomicNET project: " + folder;
+                    EditorUI.showModalError("New Project Editor Error", message);
+                    return false;
                 }
+            }
 
-                this.hide();
+            this.hide();
 
-                this.sendEvent(EditorEvents.LoadProject, { path: folder });
-                return true;
-            } else {
-                let message = [
-                    "Unable to create project for:",
-                    "",
-                    `language: ${selectedLanguage}`,
-                    `template: ${templateFolder}`,
-                    "",
-                    "Please choose a different language."
-                ].join("\n");
+            this.sendEvent(EditorEvents.LoadProject, { path: folder });
+            return true;
+        } else {
+            let message = [
+                "Unable to create project for:",
+                "",
+                `language: ${selectedLanguage}`,
+                `template: ${templateFolder}`,
+                "",
+                "Please choose a different language."
+            ].join("\n");
 
-                EditorUI.showModalError("New Project Editor Error", message);
-                return false;
-            }
+            EditorUI.showModalError("New Project Editor Error", message);
+            return false;
         }
 
-        return false;
     }
 
     handleLanguageSwitch(selectedLanguage:string) {
@@ -364,6 +380,8 @@ class CreateProject extends ModalWindow {
     iosButton: Atomic.UIButton;
     html5Button: Atomic.UIButton;
 
+    // if we have specified a projectPath, the dest will not be the combination of path + name
+    projectPath: string;
     projectTemplate: ProjectTemplates.ProjectTemplateDefinition;
 }
 

+ 2 - 2
Script/AtomicEditor/ui/modal/ModalOps.ts

@@ -65,11 +65,11 @@ class ModalOps extends Atomic.ScriptObject {
 
     }
 
-    showCreateProject(projectTemplateDefinition: ProjectTemplates.ProjectTemplateDefinition) {
+    showCreateProject(projectTemplateDefinition: ProjectTemplates.ProjectTemplateDefinition, projectPath?: string) {
 
         if (this.show()) {
 
-            this.opWindow = new CreateProject(projectTemplateDefinition);
+            this.opWindow = new CreateProject(projectTemplateDefinition, projectPath);
 
         }
 

+ 1 - 0
Script/TypeScript/AtomicWork.d.ts

@@ -301,6 +301,7 @@ declare module Atomic {
     export function destroy(component: Atomic.JSComponent): boolean;
 
     export function getParentPath(path: string): string;
+    export function getPath(path: string): string;
     export function addTrailingSlash(path: string): string;
     export function getExtension(path: string): string;
 

+ 12 - 0
Source/AtomicJS/Javascript/JSFileSystem.cpp

@@ -81,6 +81,15 @@ static int Atomic_GetParentPath(duk_context* ctx)
     return 1;
 }
 
+static int Atomic_GetPath(duk_context* ctx)
+{
+    String path = duk_require_string(ctx, 0);
+
+    duk_push_string(ctx, GetPath(path).CString());
+
+    return 1;
+}
+
 static int FileSystem_ScanDir(duk_context* ctx)
 {
     duk_push_this(ctx);
@@ -126,6 +135,9 @@ void jsapi_init_filesystem(JSVM* vm)
     duk_push_c_function(ctx, Atomic_AddTrailingSlash, 1);
     duk_put_prop_string(ctx, -2, "addTrailingSlash");
 
+    duk_push_c_function(ctx, Atomic_GetPath, 1);
+    duk_put_prop_string(ctx, -2, "getPath");
+
     duk_push_c_function(ctx, Atomic_GetParentPath, 1);
     duk_put_prop_string(ctx, -2, "getParentPath");