Browse Source

Merge pull request #1036 from AtomicGameEngine/JME-ATOMICNET-PROJECT

AtomicNET New Project support
JoshEngebretson 9 years ago
parent
commit
febdfa27d0
28 changed files with 742 additions and 75 deletions
  1. 1 0
      .gitignore
  2. 62 0
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/MainActivity.cs
  3. 5 0
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/Properties/AndroidManifest.xml
  4. 30 0
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/Properties/AssemblyInfo.cs
  5. 80 0
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/Resources/Resource.Designer.cs
  6. BIN
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/Resources/drawable/icon.png
  7. 4 0
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/Resources/values/Strings.xml
  8. 0 0
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Desktop/Program.cs
  9. 24 0
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/iOS/AppUIDelegate.cs
  10. 6 0
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/iOS/Entitlements.plist
  11. 38 0
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/iOS/Info.plist
  12. 13 0
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/iOS/Main.cs
  13. 36 0
      Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/iOS/Properties/AssemblyInfo.cs
  14. 0 17
      Data/AtomicEditor/ProjectTemplates/Project2D/CSharp/Project/AtomicNET/Platforms/Desktop/Program.cs
  15. 0 17
      Data/AtomicEditor/ProjectTemplates/Project3D/CSharp/Project/AtomicNET/Platforms/Desktop/Program.cs
  16. BIN
      Resources/EditorData/AtomicEditor/editor/images/Android128.png
  17. BIN
      Resources/EditorData/AtomicEditor/editor/images/Desktop128.png
  18. BIN
      Resources/EditorData/AtomicEditor/editor/images/HTML5128.png
  19. BIN
      Resources/EditorData/AtomicEditor/editor/images/green_plus.png
  20. BIN
      Resources/EditorData/AtomicEditor/editor/images/iOS128.png
  21. 36 26
      Resources/EditorData/AtomicEditor/editor/ui/createproject.tb.txt
  22. 235 0
      Script/AtomicEditor/resources/ProjectTemplates.ts
  23. 132 1
      Script/AtomicEditor/ui/modal/CreateProject.ts
  24. 3 5
      Script/AtomicEditor/ui/modal/info/AtomicNETWindow.ts
  25. 17 0
      Source/Atomic/UI/UIButton.cpp
  26. 4 0
      Source/Atomic/UI/UIButton.h
  27. 14 7
      Source/ToolCore/NETTools/NETProjectGen.cpp
  28. 2 2
      Source/ToolCore/ToolEnvironment.cpp

+ 1 - 0
.gitignore

@@ -21,3 +21,4 @@ node_modules/*
 Script/TypeScript/**/*.d.ts
 !Script/TypeScript/**/*Work.d.ts
 Script/Haxe/*
+**/.vscode

+ 62 - 0
Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/MainActivity.cs

@@ -0,0 +1,62 @@
+using Android.App;
+using Android.Content.PM;
+using Android.Widget;
+using Android.OS;
+using Android.Views;
+using AtomicEngine;
+
+namespace AtomicPlayer
+{
+    [Activity(Label = "AtomicPlayer", MainLauncher = true,
+        Icon = "@drawable/icon", Theme = "@android:style/Theme.NoTitleBar.Fullscreen",
+        ConfigurationChanges = ConfigChanges.KeyboardHidden | ConfigChanges.Orientation,
+        ScreenOrientation = ScreenOrientation.Landscape)]
+    public class MainActivity : Activity
+    {
+        protected override void OnCreate(Bundle bundle)
+        {
+            base.OnCreate(bundle);
+            var mLayout = new AbsoluteLayout(this);
+            var surface = AndroidSDLSurface.CreateSurface(this, false, typeof(AtomicMain));
+            mLayout.AddView(surface);
+            SetContentView(mLayout);
+        }
+
+        protected override void OnResume()
+        {
+            AndroidSDLSurface.OnResume();
+            base.OnResume();
+        }
+
+        protected override void OnPause()
+        {
+            AndroidSDLSurface.OnPause();
+            base.OnPause();
+        }
+
+        public override void OnLowMemory()
+        {
+            AndroidSDLSurface.OnLowMemory();
+            base.OnLowMemory();
+        }
+
+        protected override void OnDestroy()
+        {
+            AndroidSDLSurface.OnDestroy();
+            base.OnDestroy();
+        }
+
+        public override bool DispatchKeyEvent(KeyEvent e)
+        {
+            if (!AndroidSDLSurface.DispatchKeyEvent(e))
+                return false;
+            return base.DispatchKeyEvent(e);
+        }
+
+        public override void OnWindowFocusChanged(bool hasFocus)
+        {
+            AndroidSDLSurface.OnWindowFocusChanged(hasFocus);
+            base.OnWindowFocusChanged(hasFocus);
+        }
+    }
+}

+ 5 - 0
Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/Properties/AndroidManifest.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="$$APPLICATION_NAME$$.$$APPLICATION_NAME$$" android:versionCode="1" android:versionName="1.0">
+	<uses-sdk android:minSdkVersion="16" />
+	<application android:label="$$APPLICATION_NAME$$"></application>
+</manifest>

+ 30 - 0
Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/Properties/AssemblyInfo.cs

@@ -0,0 +1,30 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using Android.App;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("$$APPLICATION_NAME$$")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("$$APPLICATION_NAME$$")]
+[assembly: AssemblyCopyright("Copyright © 2016")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+[assembly: ComVisible(false)]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 80 - 0
Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/Resources/Resource.Designer.cs

@@ -0,0 +1,80 @@
+#pragma warning disable 1591
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+[assembly: global::Android.Runtime.ResourceDesignerAttribute("Application.Resource", IsApplication=true)]
+
+namespace Application
+{
+
+
+    [System.CodeDom.Compiler.GeneratedCodeAttribute("Xamarin.Android.Build.Tasks", "1.0.0.0")]
+    public partial class Resource
+    {
+
+        static Resource()
+        {
+            global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+        }
+
+        public static void UpdateIdValues()
+        {
+        }
+
+        public partial class Attribute
+        {
+
+            static Attribute()
+            {
+                global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+            }
+
+            private Attribute()
+            {
+            }
+        }
+
+        public partial class Drawable
+        {
+
+            // aapt resource value: 0x7f020000
+            public const int icon = 2130837504;
+
+            static Drawable()
+            {
+                global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+            }
+
+            private Drawable()
+            {
+            }
+        }
+
+        public partial class String
+        {
+
+            // aapt resource value: 0x7f030001
+            public const int ApplicationName = 2130903041;
+
+            // aapt resource value: 0x7f030000
+            public const int app_name = 2130903040;
+
+            static String()
+            {
+                global::Android.Runtime.ResourceIdManager.UpdateIdValues();
+            }
+
+            private String()
+            {
+            }
+        }
+    }
+}
+#pragma warning restore 1591

BIN
Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/Resources/drawable/icon.png


+ 4 - 0
Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Android/Resources/values/Strings.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="ApplicationName">$$APPLICATION_NAME$$</string>
+</resources>

+ 0 - 0
Data/AtomicEditor/ProjectTemplates/EmptyProject/CSharp/Project/AtomicNET/Platforms/Desktop/Program.cs → Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/Desktop/Program.cs


+ 24 - 0
Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/iOS/AppUIDelegate.cs

@@ -0,0 +1,24 @@
+using Foundation;
+using UIKit;
+using System.Threading.Tasks;
+
+using AtomicEngine;
+
+namespace AtomicPlayer
+{
+    [Register("AppUIDelegate")]
+    public partial class AppUIDelegate : UIApplicationDelegate
+    {
+        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
+        {
+            LaunchGame();
+            return true;
+        }
+
+        async void LaunchGame()
+        {
+            await Task.Yield();
+            Application.Run<AtomicMain>(new string[0]);
+        }
+    }
+}

+ 6 - 0
Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/iOS/Entitlements.plist

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+	<dict>
+	</dict>
+</plist>

+ 38 - 0
Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/iOS/Info.plist

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleIdentifier</key>
+	<string>$$APPLICATION_ID$$</string>
+	<key>CFBundleShortVersionString</key>
+	<string>1.0</string>
+	<key>CFBundleVersion</key>
+	<string>1.0</string>
+	<key>UIDeviceFamily</key>
+	<array>
+		<integer>1</integer>
+		<integer>2</integer>
+	</array>
+	<key>UISupportedInterfaceOrientations</key>
+	<array>
+		<string>UIInterfaceOrientationLandscapeLeft</string>
+		<string>UIInterfaceOrientationLandscapeRight</string>
+	</array>
+	<key>UISupportedInterfaceOrientations~ipad</key>
+	<array>
+		<string>UIInterfaceOrientationLandscape</string>
+	</array>
+	<key>MinimumOSVersion</key>
+	<string>9.3</string>
+	<key>CFBundleIconFiles</key>
+	<array>
+		<string>Data/Icon</string>
+	</array>
+	<key>UIStatusBarHidden</key>
+	<true/>
+	<key>CFBundleName</key>
+	<string>$$APPLICATION_NAME$$</string>
+	<key>UIRequiresFullScreen</key>
+	<true/>
+</dict>
+</plist>

+ 13 - 0
Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/iOS/Main.cs

@@ -0,0 +1,13 @@
+using UIKit;
+
+namespace AtomicPlayer
+{
+    public class AtomicApp
+    {
+        // This is the main entry point of the application.
+        static void Main(string[] args)
+        {
+            UIApplication.Main(args, null, "AppUIDelegate");
+        }
+    }
+}

+ 36 - 0
Data/AtomicEditor/AtomicNET/ProjectTemplate/Platforms/iOS/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("$$APPLICATION_NAME$$")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("$$APPLICATION_NAME$$")]
+[assembly: AssemblyCopyright("Copyright ©  2015")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("3a72e714-15ce-4707-ba90-e389fb7c9b2c")]
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 0 - 17
Data/AtomicEditor/ProjectTemplates/Project2D/CSharp/Project/AtomicNET/Platforms/Desktop/Program.cs

@@ -1,17 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Linq;
-
-using AtomicEngine;
-
-namespace AtomicPlayer
-{
-    public class Program
-    {
-        public static void Main(string[] args)
-        {
-            Application.Run<AtomicMain>(args);
-        }
-    }
-}

+ 0 - 17
Data/AtomicEditor/ProjectTemplates/Project3D/CSharp/Project/AtomicNET/Platforms/Desktop/Program.cs

@@ -1,17 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Reflection;
-using System.Linq;
-
-using AtomicEngine;
-
-namespace AtomicPlayer
-{
-    public class Program
-    {
-        public static void Main(string[] args)
-        {
-            Application.Run<AtomicMain>(args);
-        }
-    }
-}

BIN
Resources/EditorData/AtomicEditor/editor/images/Android128.png


BIN
Resources/EditorData/AtomicEditor/editor/images/Desktop128.png


BIN
Resources/EditorData/AtomicEditor/editor/images/HTML5128.png


BIN
Resources/EditorData/AtomicEditor/editor/images/green_plus.png


BIN
Resources/EditorData/AtomicEditor/editor/images/iOS128.png


+ 36 - 26
Resources/EditorData/AtomicEditor/editor/ui/createproject.tb.txt

@@ -1,27 +1,37 @@
 TBLayout: axis: y, distribution: gravity, position: left
-	TBLayout: distribution: gravity
-		TBLayout: distribution: gravity
-			TBTextField: text: "Project Name:"
-			TBLayout: gravity: left right, distribution-position: right bottom
-				TBEditField: id: project_name, text: "MyGame"
-					lp: min-width: 240
-		TBLayout: gravity: left right, distribution-position: right bottom
-			TBImageWidget: id: project_image
-				lp: width: 128, height: 96
-	TBSeparator: gravity: left right, skin: AESeparator
-	TBTextField: text: "Project Directory:"
-	TBLayout: axis: y, distribution: gravity, position: left
-		TBLayout: gravity: left right, distribution-position: right bottom
-			TBEditField: id: project_path
-				lp: min-width: 380
-			TBButton: text: "Choose" id: choose_path
-	TBSeparator: gravity: left right, skin: AESeparator
-	TBLayout: distribution: gravity
-		TBTextField: text: "Project Language:"
-		TBLayout: gravity: left right, distribution-position: right bottom
-			TBSelectDropdown: id: project_language
-				lp: min-width: 240
-	TBSeparator: gravity: left right, skin: AESeparator
-	TBLayout:
-		TBButton: text: Create, id: create
-		TBButton: text: Cancel, id: cancel
+    TBLayout: distribution: gravity, axis: y
+        TBLayout: distribution: gravity
+            TBLayout: distribution: gravity, axis: y
+                TBLayout: distribution: gravity
+                    TBTextField: text: "Project Name:"
+                    TBLayout: gravity: left right, distribution-position: right bottom
+                        TBEditField: id: project_name, text: "MyGame"
+                            lp: min-width: 240
+                TBLayout: distribution: gravity
+                    TBTextField: text: "App ID:"
+                    TBLayout: gravity: left right, distribution-position: right bottom
+                        TBEditField: id: app_id, text: "com.companyname.mygame"
+                            lp: min-width: 240
+            TBLayout: gravity: left right, distribution-position: right bottom
+                TBImageWidget: id: project_image
+                    lp: width: 128, height: 96
+    TBSeparator: gravity: left right, skin: AESeparator
+    TBTextField: text: "Platforms:"
+    TBLayout: id: platformcontainer
+    TBSeparator: gravity: left right, skin: AESeparator
+    TBTextField: text: "Project Directory:"
+    TBLayout: axis: y, distribution: gravity, position: left
+        TBLayout: gravity: left right, distribution-position: right bottom
+            TBEditField: id: project_path
+                lp: min-width: 380
+            TBButton: text: "Choose" id: choose_path
+    TBSeparator: gravity: left right, skin: AESeparator
+    TBLayout: distribution: gravity
+        TBTextField: text: "Project Language:"
+        TBLayout: gravity: left right, distribution-position: right bottom
+            TBSelectDropdown: id: project_language
+                lp: min-width: 240
+    TBSeparator: gravity: left right, skin: AESeparator
+    TBLayout:
+        TBButton: text: Create, id: create
+        TBButton: text: Cancel, id: cancel

+ 235 - 0
Script/AtomicEditor/resources/ProjectTemplates.ts

@@ -112,3 +112,238 @@ export function GetNewFileTemplateDefinitions(fileTemplateType: string) : Editor
     const templates = JSON.parse(file.readText());
     return templates[fileTemplateType] || [];
 }
+
+// AtomicNET
+
+export interface AtomicNETProjectInfo {
+    name: string;
+    appID: string;
+    platforms: string[];
+    projectFolder: string;
+}
+
+var atomicNETProjectInfo:AtomicNETProjectInfo;
+
+/**
+ * Processes an AtomicNET template, replacing strings with settings
+ * @param  {string} filename
+ * @param  {string} templateFilename
+ * @return {boolean}
+ */
+function processAtomicNETTemplate(filename:string, templateFilename:string) : boolean {
+
+    let file = new Atomic.File(templateFilename, Atomic.FILE_READ);
+
+    if (!file.isOpen()) {
+        console.log("Failed to open: ", templateFilename);
+        return false;
+    }
+
+    let text = file.readText();
+
+    text = text.split("$$APPLICATION_NAME$$").join(atomicNETProjectInfo.name);
+    text = text.split("$$APPLICATION_ID$$").join(atomicNETProjectInfo.appID);
+
+    let fileOut = new Atomic.File(filename, Atomic.FILE_WRITE);
+
+    if (!fileOut.isOpen()) {
+        console.log("Failed to open for write: ", filename);
+        return false;
+    }
+
+    fileOut.writeString(text);
+
+    file.close();
+
+    return true;
+}
+
+/**
+ * Generates the Android portion of an AtomicNET project
+ * @return {boolean}
+ */
+function generateAtomicNETAndroidProject():boolean {
+
+    let env = ToolCore.toolEnvironment;
+    let utils = new Editor.FileUtils();
+    let templateFolder = env.toolDataDir + "AtomicNET/ProjectTemplate/";
+    let androidFolder = Atomic.addTrailingSlash(atomicNETProjectInfo.projectFolder) + "Project/AtomicNET/Platforms/Android/";
+
+    let fileSystem = Atomic.fileSystem;
+
+    // Create necessary folders
+    let folders = ["Properties", "Resources/drawable", "Resources/values"];
+    for (var i = 0; i < folders.length; i++) {
+
+        let folder = androidFolder + folders[i];
+
+        if (!fileSystem.dirExists(folder)) {
+
+            if (!utils.createDirs(folder))
+                return false;
+        }
+
+    }
+
+    let textFiles = [".cs", ".xml"];
+
+    let files = ["MainActivity.cs", "Resources/Resource.Designer.cs", "Resources/drawable/icon.png",
+                 "Resources/values/Strings.xml", "Properties/AndroidManifest.xml", "Properties/AssemblyInfo.cs"];
+
+    for (var i = 0; i < files.length; i++) {
+
+        let templateName = templateFolder + "Platforms/Android/" + files[i];
+        let filename = androidFolder + files[i];
+
+        if (textFiles.indexOf(Atomic.getExtension(templateName)) == -1) {
+
+            if (!fileSystem.copy(templateName, filename)) {
+
+                console.log("Failed to copy: ", templateName, " to ",  filename);
+                return false;
+            }
+
+        } else {
+
+            if (!processAtomicNETTemplate(filename, templateName)) {
+                return false;
+            }
+
+        }
+
+    }
+
+    return true;
+}
+
+/**
+ * Generates the iOS portion of an AtomicNET project
+ * @return {boolean}
+ */
+function generateAtomicNETIOSProject():boolean {
+
+    let env = ToolCore.toolEnvironment;
+    let utils = new Editor.FileUtils();
+    let templateFolder = env.toolDataDir + "AtomicNET/ProjectTemplate/";
+    let iosFolder = Atomic.addTrailingSlash(atomicNETProjectInfo.projectFolder) + "Project/AtomicNET/Platforms/iOS/";
+
+    let fileSystem = Atomic.fileSystem;
+
+    // Create necessary folders
+    let folders = ["Properties", "Resources"];
+    for (var i = 0; i < folders.length; i++) {
+
+        let folder = iosFolder + folders[i];
+
+        if (!fileSystem.dirExists(folder)) {
+
+            if (!utils.createDirs(folder))
+                return false;
+        }
+
+    }
+
+    let textFiles = [".cs", ".plist"];
+
+    let files = ["Main.cs", "AppUIDelegate.cs", "Entitlements.plist", "Info.plist",
+                 "Properties/AssemblyInfo.cs"];
+
+    for (var i = 0; i < files.length; i++) {
+
+        let templateName = templateFolder + "Platforms/iOS/" + files[i];
+        let filename = iosFolder + files[i];
+
+        if (textFiles.indexOf(Atomic.getExtension(templateName)) == -1) {
+
+            if (!fileSystem.copy(templateName, filename)) {
+
+                console.log("Failed to copy: ", templateName, " to ",  filename);
+                return false;
+            }
+
+        } else {
+
+            if (!processAtomicNETTemplate(filename, templateName)) {
+                return false;
+            }
+
+        }
+
+    }
+
+    return true;
+}
+
+
+/**
+ * Generates the Desktop portion of an AtomicNET project
+ * @return {boolean}
+ */
+function generateAtomicNETDesktopProject():boolean {
+
+    let env = ToolCore.toolEnvironment;
+    let utils = new Editor.FileUtils();
+    let templateFolder = env.toolDataDir + "AtomicNET/ProjectTemplate/";
+    let desktopFolder = Atomic.addTrailingSlash(atomicNETProjectInfo.projectFolder) + "Project/AtomicNET/Platforms/Desktop/";
+
+    let fileSystem = Atomic.fileSystem;
+
+    if (!fileSystem.dirExists(desktopFolder)) {
+
+        if (!utils.createDirs(desktopFolder))
+            return false;
+    }
+
+    if (!fileSystem.copy(templateFolder + "Platforms/Desktop/Program.cs", desktopFolder + "Program.cs")) {
+        return false;
+    }
+
+    return true;
+}
+
+
+/**
+ * Generates an AtomicNET project from templates
+ * @param  {AtomicNETProjectInfo} projectInfo
+ * @return {boolean}
+ */
+export function generateAtomicNETProject(projectInfo:AtomicNETProjectInfo):boolean {
+
+    atomicNETProjectInfo = projectInfo;
+
+    let env = ToolCore.toolEnvironment;
+    let templateFolder = env.toolDataDir + "AtomicNET/ProjectTemplate/";
+    let platformsFolder = Atomic.addTrailingSlash(projectInfo.projectFolder) + "Project/AtomicNET/Platforms/";
+
+    let utils = new Editor.FileUtils();
+    let fileSystem = Atomic.fileSystem;
+
+    if (!fileSystem.dirExists(platformsFolder)) {
+
+        if (!utils.createDirs(platformsFolder))
+            return false;
+    }
+
+    if (!generateAtomicNETDesktopProject()) {
+        return false;
+    }
+
+    if (projectInfo.platforms.indexOf("android") != -1) {
+
+        if (!generateAtomicNETAndroidProject()) {
+            return false;
+        }
+
+    }
+
+    if (projectInfo.platforms.indexOf("ios") != -1) {
+
+        if (!generateAtomicNETIOSProject()) {
+            return false;
+        }
+
+    }
+
+
+    return true;
+}

+ 132 - 1
Script/AtomicEditor/ui/modal/CreateProject.ts

@@ -38,15 +38,21 @@ class CreateProject extends ModalWindow {
 
         this.projectPathField = <Atomic.UIEditField>this.getWidget("project_path");
         this.projectNameField = <Atomic.UIEditField>this.getWidget("project_name");
+        this.appIDField = <Atomic.UIEditField>this.getWidget("app_id");
         this.projectLanguageField = <Atomic.UISelectDropdown>this.getWidget("project_language");
         this.image = <Atomic.UIImageWidget>this.getWidget("project_image");
 
+        this.desktopButton = this.addPlatformButton("desktop", "AtomicEditor/editor/images/Desktop128.png");
+        this.desktopButton.value = 1;
+        this.androidButton = this.addPlatformButton("android", "AtomicEditor/editor/images/Android128.png");
+        this.iosButton = this.addPlatformButton("ios", "AtomicEditor/editor/images/iOS128.png");
+        this.html5Button = this.addPlatformButton("html5", "AtomicEditor/editor/images/HTML5128.png");
+
         if (!projectTemplate.screenshot)
             this.image.visibility = Atomic.UI_WIDGET_VISIBILITY_GONE;
         else
             this.image.image = projectTemplate.screenshot;
 
-
         var fileSystem = Atomic.getFileSystem();
 
         var userDocuments = fileSystem.userDocumentsDir;
@@ -72,6 +78,50 @@ class CreateProject extends ModalWindow {
 
     }
 
+    addPlatformButton(platformName:string, platformLogo:string):Atomic.UIButton {
+
+        var platformcontainer = <Atomic.UILayout>this.getWidget("platformcontainer");
+
+        // IMAGE BUTTON
+
+        var id = platformName;
+        var size = 92;
+
+        var button = new Atomic.UIButton();
+        button.id = id;
+        button.toggleMode = true;
+
+        var lp = new Atomic.UILayoutParams();
+        lp.minWidth = size;
+        lp.minHeight = size;
+
+        button.layoutParams = lp;
+
+        button.gravity = Atomic.UI_GRAVITY_ALL;
+
+        var image = new Atomic.UIImageWidget();
+        image.image = platformLogo;
+        var rect = [0, 0, size, size];
+        image.rect = rect;
+        button.addChild(image);
+
+        if (platformName != "desktop") {
+            var greenplus = new Atomic.UIImageWidget();
+            greenplus.image = "AtomicEditor/editor/images/green_plus.png";
+            rect = [size-18, 2, size-2, 18];
+            greenplus.rect = rect;
+            greenplus.visibility = Atomic.UI_WIDGET_VISIBILITY_INVISIBLE;
+            button.addChild(greenplus);
+            button["greenPlus"] = greenplus;
+        }
+
+        platformcontainer.addChild(button);
+
+        return button;
+
+    }
+
+
     tryProjectCreate(): boolean {
 
         var name = this.projectNameField.text.trim();
@@ -109,8 +159,10 @@ class CreateProject extends ModalWindow {
             let selectedLanguage = this.projectLanguageField.text;
 
             // 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();
@@ -137,6 +189,7 @@ class CreateProject extends ModalWindow {
                 var utils = new Editor.FileUtils();
 
                 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";
@@ -160,6 +213,44 @@ class CreateProject extends ModalWindow {
                     fileSystem.rename(folder + fileResults[0], folder + name + ".userprefs");
                 }
 
+                // create project settings
+
+                var platforms = ["desktop"];
+
+                if (this.androidButton.value == 1) {
+                    platforms.push("android");
+                }
+
+                if (this.iosButton.value == 1) {
+                    platforms.push("ios");
+                }
+
+                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();
+                }
+
+                // Generate AtomicNET project if necessary
+                if (atomicNET) {
+                    if (!ProjectTemplates.generateAtomicNETProject({
+                        name: name,
+                        appID : this.appIDField.text,
+                        platforms : platforms,
+                        projectFolder : folder
+                    })) {
+                        var message = "Unable to generate AtomicNET project: " + folder;
+                        EditorUI.showModalError("New Project Editor Error", message);
+                        return false;
+                    }
+                }
+
                 this.hide();
 
                 this.sendEvent(EditorEvents.LoadProject, { path: folder });
@@ -181,6 +272,23 @@ class CreateProject extends ModalWindow {
         return false;
     }
 
+    handleLanguageSwitch(selectedLanguage:string) {
+
+        if (selectedLanguage == "CSharp" || selectedLanguage == "C#") {
+
+            this.html5Button["greenPlus"].visibility = Atomic.UI_WIDGET_VISIBILITY_INVISIBLE;
+            this.html5Button.value = 0;
+            this.html5Button.disable();
+
+        } else {
+
+            this.html5Button.enable();
+            this.html5Button["greenPlus"].visibility = this.html5Button.value == 1 ? Atomic.UI_WIDGET_VISIBILITY_VISIBLE : Atomic.UI_WIDGET_VISIBILITY_INVISIBLE;
+
+        }
+
+    }
+
     handleWidgetEvent(ev: Atomic.UIWidgetEvent) {
 
         if (ev.type == Atomic.UI_EVENT_TYPE_CLICK) {
@@ -207,6 +315,23 @@ class CreateProject extends ModalWindow {
                 return true;
 
             }
+        } else if (ev.type == Atomic.UI_EVENT_TYPE_CHANGED) {
+
+            // handle language change
+            if (ev.target.id == "project_language") {
+                this.handleLanguageSwitch(this.projectLanguageField.text);
+            }
+
+            if (ev.target.id == "desktop") {
+
+                // desktop is always selected
+                this.desktopButton.value = 1;
+
+            } else if (ev.target["greenPlus"]) {
+                ev.target["greenPlus"].visibility = ev.target.value == 1 ? Atomic.UI_WIDGET_VISIBILITY_VISIBLE : Atomic.UI_WIDGET_VISIBILITY_INVISIBLE;
+            }
+
+
         }
     }
 
@@ -227,10 +352,16 @@ class CreateProject extends ModalWindow {
 
     projectPathField: Atomic.UIEditField;
     projectNameField: Atomic.UIEditField;
+    appIDField: Atomic.UIEditField;
     projectLanguageField: Atomic.UISelectDropdown;
     projectLanguageFieldSource: Atomic.UISelectItemSource = new Atomic.UISelectItemSource();
     image: Atomic.UIImageWidget;
 
+    desktopButton: Atomic.UIButton;
+    androidButton: Atomic.UIButton;
+    iosButton: Atomic.UIButton;
+    html5Button: Atomic.UIButton;
+
     projectTemplate: ProjectTemplates.ProjectTemplateDefinition;
 }
 

+ 3 - 5
Script/AtomicEditor/ui/modal/info/AtomicNETWindow.ts

@@ -75,15 +75,13 @@ class AtomicNETWindow extends ModalWindow {
 
     generateAtomicNETText(): string {
 
-        var installText:string;
+        let ideText:string = Atomic.platform == "Windows" ? "Visual Studio" : "Xamarin Studio";
 
-        var ideText:string = Atomic.platform == "Windows" ? "Visual Studio" : "Xamarin Studio";
-
-        var installText = `Please install ${ideText} with <color #D4FB79>Xamarin.Android</color> and <color #D4FB79>Xamarin.iOS</color>`;
+        let installText = `Please install ${ideText} with <color #D4FB79>Xamarin.Android</color> and <color #D4FB79>Xamarin.iOS</color>`;
 
         this.downloadButton.text = `Download ${ideText}`;
 
-        var text = "";
+        let text = "";
 
         text += `
 Atomic C# is integrated with <color #D4FB79>Visual Studio</color> and <color #D4FB79>Xamarin Studio</color> to provide a first class editing, debugging, and deployment experience.

+ 17 - 0
Source/Atomic/UI/UIButton.cpp

@@ -60,6 +60,23 @@ void UIButton::SetSqueezable(bool value)
     ((TBButton*)widget_)->SetSqueezable(value);
 }
 
+void UIButton::SetToggleMode(bool toggle)
+{
+    if (!widget_)
+        return;
+
+    ((TBButton*)widget_)->SetToggleMode(toggle);
+
+}
+
+bool UIButton::GetToggleMode() const
+{
+    if (!widget_)
+        return false;
+
+    return ((TBButton*)widget_)->GetToggleMode();
+}
+
 void UIButton::SetEmulationButton(int emulationButton)
 {
     emulationButton_ = emulationButton;

+ 4 - 0
Source/Atomic/UI/UIButton.h

@@ -50,6 +50,10 @@ public:
     /// for example a http:// link will open the default browser
     void SetURLEnabled(bool enabled) { urlEnabled_ = enabled; }
 
+    ///Set to true if the button should toggle on and off    
+    void SetToggleMode(bool toggle);
+    bool GetToggleMode() const;
+
 protected:
 
     virtual bool OnEvent(const tb::TBWidgetEvent &ev);

+ 14 - 7
Source/ToolCore/NETTools/NETProjectGen.cpp

@@ -837,17 +837,17 @@ namespace ToolCore
         // OutputType
         XMLElement outputType = pgroup.CreateChild("OutputType");
 
-		String oType = outputType_;
+        String oType = outputType_;
 
 #ifdef ATOMIC_PLATFORM_WINDOWS
 #ifndef ATOMIC_DEBUG
 
-		if (oType.ToLower() == "exe") 
-		{
-			// use windows subsystem for release builds
-			// TODO: make this an option in the json?
-			oType = "WinExe";
-		}
+        if (oType.ToLower() == "exe") 
+        {
+            // use windows subsystem for release builds
+            // TODO: make this an option in the json?
+            oType = "WinExe";
+        }
 
 #endif
 #endif
@@ -1114,9 +1114,16 @@ namespace ToolCore
                     String startArguments;
 
 #ifndef ATOMIC_DEV_BUILD
+
+#ifdef ATOMIC_PLATFORM_OSX
+                    startArguments += ToString("--resourcePrefix \"%s\" ", (fileSystem->GetProgramDir() + "../Resources/").CString());
+#else
                     startArguments += ToString("--resourcePrefix \"%s\" ", (fileSystem->GetProgramDir() + "Resources/").CString());
 #endif
 
+#endif
+
+
                     propertyGroup.CreateChild("StartAction").SetValue("Project");
 
                     startArguments += ToString("--project \"%s\"", atomicProjectPath.CString());

+ 2 - 2
Source/ToolCore/ToolEnvironment.cpp

@@ -79,9 +79,9 @@ bool ToolEnvironment::InitFromPackage()
     // atomicNETNuGetBinary_ = ToString("%sBuild/Managed/nuget/nuget.exe", rootSourceDir_.CString());       
 
 #ifdef ATOMIC_DEBUG
-	String config = "Debug";
+    String config = "Debug";
 #else
-	String config = "Release";
+    String config = "Release";
 #endif
 
     atomicNETRootDir_ = resourcesDir + "ToolData/AtomicNET/";