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

Refactoring example's to store info in the AtomicExamples repo, adding logic to load from example repo directly, updating example browser to load example info from repo

Josh Engebretson 9 лет назад
Родитель
Сommit
86a09659b9
36 измененных файлов с 283 добавлено и 278 удалено
  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. 1 2
      Script/AtomicEditor/ui/frames/WelcomeFrame.ts
  32. 3 3
      Script/AtomicEditor/ui/frames/menus/MainFrameMenu.ts
  33. 111 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);
+
+        }
+
+    }
 
 }
 

+ 1 - 2
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 });
 
                 }
 

+ 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();
 
                 }
 

+ 111 - 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
@@ -138,139 +145,141 @@ class CreateProject extends ModalWindow {
             return false;
         }
 
-        folder += "/" + name;
-
         var fileSystem = Atomic.getFileSystem();
 
-        if (fileSystem.dirExists(folder) || fileSystem.fileExists(folder)) {
+        if (!this.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 (!this.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 +373,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");