Browse Source

Atomic Editor, copyright notice

Josh Engebretson 11 years ago
parent
commit
77b30b8fb7
100 changed files with 3917 additions and 1 deletions
  1. 0 1
      .gitignore
  2. 42 0
      AtomicEditor/CMakeLists.txt
  3. 3 0
      AtomicEditor/EditorApplicationData/Deployment/Android/assets/.gitignore
  4. 83 0
      AtomicEditor/EditorApplicationData/Deployment/Android/build.xml
  5. BIN
      AtomicEditor/EditorApplicationData/Deployment/Android/res/drawable-hdpi/icon.png
  6. BIN
      AtomicEditor/EditorApplicationData/Deployment/Android/res/drawable-ldpi/icon.png
  7. BIN
      AtomicEditor/EditorApplicationData/Deployment/Android/res/drawable-mdpi/icon.png
  8. BIN
      AtomicEditor/EditorApplicationData/Deployment/Android/res/drawable/logo_large.png
  9. 25 0
      AtomicEditor/EditorApplicationData/Deployment/Android/res/layout/samples_list.xml
  10. 11 0
      AtomicEditor/EditorApplicationData/Deployment/Android/res/layout/samples_list_text_view.xml
  11. 0 0
      AtomicEditor/EditorApplicationData/Deployment/Android/res/values/.gitkeep
  12. 1112 0
      AtomicEditor/EditorApplicationData/Deployment/Android/src/org/libsdl/app/SDLActivity.java
  13. 0 0
      AtomicEditor/EditorApplicationData/Deployment/MacOS/.gitkeep
  14. 43 0
      AtomicEditor/EditorApplicationData/Deployment/MacOS/AtomicPlayer.app/Contents/Info.plist
  15. BIN
      AtomicEditor/EditorApplicationData/Deployment/MacOS/AtomicPlayer.app/Contents/Resources/Atomic.icns
  16. BIN
      AtomicEditor/EditorApplicationData/ExampleInfo/CharacterAnimation3D.png
  17. 41 0
      AtomicEditor/EditorApplicationData/ExampleInfo/Examples.json
  18. BIN
      AtomicEditor/EditorApplicationData/ExampleInfo/Light2D.png
  19. BIN
      AtomicEditor/EditorApplicationData/ExampleInfo/PhysicsPlatformer2D.png
  20. BIN
      AtomicEditor/EditorApplicationData/ExampleInfo/Roboman3D.png
  21. BIN
      AtomicEditor/EditorApplicationData/ExampleInfo/SpaceGame.png
  22. BIN
      AtomicEditor/EditorApplicationData/ExampleInfo/UIExample.png
  23. 0 0
      AtomicEditor/EditorApplicationData/ProjectTemplates/EmptyProject/EmptyProject.atomic
  24. 0 0
      AtomicEditor/EditorApplicationData/ProjectTemplates/EmptyProject/Resources/Components/.gitkeep
  25. 17 0
      AtomicEditor/EditorApplicationData/ProjectTemplates/EmptyProject/Resources/Scripts/main.js
  26. 0 0
      AtomicEditor/EditorApplicationData/ProjectTemplates/Project2D/Project2D.atomic
  27. 16 0
      AtomicEditor/EditorApplicationData/ProjectTemplates/Project2D/Resources/Components/Star.js
  28. 25 0
      AtomicEditor/EditorApplicationData/ProjectTemplates/Project2D/Resources/Scripts/main.js
  29. BIN
      AtomicEditor/EditorApplicationData/ProjectTemplates/Project2D/Resources/Sprites/star.png
  30. 0 0
      AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Project3D.atomic
  31. 21 0
      AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Resources/Components/Chest.js
  32. 5 0
      AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Resources/Materials/Chest.xml
  33. BIN
      AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Resources/Models/Chest.mdl
  34. 46 0
      AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Resources/Scripts/main.js
  35. BIN
      AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Resources/Textures/chest.png
  36. 28 0
      AtomicEditor/EditorResources/AtomicEditor/Modules/AtomicEditor.js
  37. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/images/atomic_logo.png
  38. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/images/newproject_2d.png
  39. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/images/newproject_3d.png
  40. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/images/newproject_empty.png
  41. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/bg_tile.png
  42. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/component.png
  43. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/file.png
  44. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/folder.png
  45. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/folder_create.png
  46. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/folder_delete.png
  47. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/image_frame.png
  48. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/item_separator_x.png
  49. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/javascript.png
  50. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_android.png
  51. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_atomic_64.png
  52. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_html5.png
  53. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_ios.png
  54. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_mac.png
  55. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_windows.png
  56. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/magnifier.png
  57. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/play.png
  58. 104 0
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/skin.tb.txt
  59. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/star_gold.png
  60. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]
  61. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]
  62. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]
  63. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/star_gray.png
  64. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]
  65. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]
  66. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]
  67. BIN
      AtomicEditor/EditorResources/AtomicEditor/editor/skin/window.png
  68. 6 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/about.tb.txt
  69. 22 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/activation.tb.txt
  70. 6 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/activationsuccess.tb.txt
  71. 12 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/build.tb.txt
  72. 14 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/buildsettings.tb.txt
  73. 42 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/buildsettings_android.tb.txt
  74. 29 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/buildsettings_windows.tb.txt
  75. 5 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/consolewidget.tb.txt
  76. 4 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/errorswidget.tb.txt
  77. 22 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/findtextwidget.tb.txt
  78. 4 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/issueswidget.tb.txt
  79. 66 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/mainframe.tb.txt
  80. 9 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/maintoolbar.tb.txt
  81. 6 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/managelicense.tb.txt
  82. 13 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/newproject.tb.txt
  83. 10 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/platformsinfo.tb.txt
  84. 2 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/playerwidget.tb.txt
  85. 9 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/programoutput.tb.txt
  86. 5 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/progressmodal.tb.txt
  87. 13 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/projectframe.tb.txt
  88. 10 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/resourcecreatecomponent.tb.txt
  89. 10 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/resourcecreatescript.tb.txt
  90. 9 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/resourcedelete.tb.txt
  91. 2 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/resourceframe.tb.txt
  92. 10 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/resourcenewfolder.tb.txt
  93. 39 0
      AtomicEditor/EditorResources/AtomicEditor/editor/ui/welcomeframe.tb.txt
  94. 99 0
      AtomicEditor/EditorResources/AtomicEditor/javascript/AtomicEditor.js
  95. 541 0
      AtomicEditor/EditorResources/AtomicEditor/javascript/modules/acorn.js
  96. 1167 0
      AtomicEditor/EditorResources/AtomicEditor/javascript/modules/acorn_loose.js
  97. 109 0
      AtomicEditor/EditorResources/AtomicEditor/javascript/modules/beautify.js
  98. BIN
      AtomicEditor/EditorResources/AtomicEditor/resources/MesloLGL-Bold.ttf
  99. BIN
      AtomicEditor/EditorResources/AtomicEditor/resources/MesloLGL-BoldItalic.ttf
  100. BIN
      AtomicEditor/EditorResources/AtomicEditor/resources/MesloLGL-Italic.ttf

+ 0 - 1
.gitignore

@@ -3,7 +3,6 @@
 Bin/Atomic.d.ts
 Bin/Atomic.d.ts
 Bin/Atomic.js
 Bin/Atomic.js
 Source/Atomic/Javascript/Modules/*
 Source/Atomic/Javascript/Modules/*
-AtomicEditor/*
 Artifacts/*
 Artifacts/*
 Docs/out/*
 Docs/out/*
 Docs/node_modules/*
 Docs/node_modules/*

+ 42 - 0
AtomicEditor/CMakeLists.txt

@@ -0,0 +1,42 @@
+
+include_directories(${CMAKE_SOURCE_DIR}/Source)
+include_directories(${CMAKE_SOURCE_DIR}/Source/ThirdParty ${CMAKE_SOURCE_DIR}/Source/ThirdParty/rapidjson/include)
+
+file (GLOB_RECURSE SOURCE_FILES Source/*.cpp Source/*.h)
+
+include_directories (${CMAKE_SOURCE_DIR}/AtomicEditor/Source)
+include_directories (${CMAKE_CURRENT_SOURCE_DIR}/Vendor/nativefiledialog)
+include_directories (${CMAKE_CURRENT_SOURCE_DIR}/Vendor/Poco/Foundation/include)
+
+add_definitions(-DPOCO_NO_AUTOMATIC_LIBS)
+
+set (SOURCE_FILES ${SOURCE_FILES} Vendor/nativefiledialog/nfd_common.c)
+
+if (APPLE)
+    set (EXE_TYPE MACOSX_BUNDLE)
+    set (SOURCE_FILES ${SOURCE_FILES} Vendor/nativefiledialog/nfd_cocoa.mm Vendor/nativefiledialog/nfd.h)
+else()
+    include_directories (${CMAKE_CURRENT_SOURCE_DIR}/Vendor/libcurl/include)
+    add_definitions(-DCURL_STATICLIB)
+    set (EXE_TYPE WIN32)
+    set (SOURCE_FILES ${SOURCE_FILES} Vendor/nativefiledialog/nfd_win.cpp Vendor/nativefiledialog/nfd.h)
+endif(APPLE)
+
+add_subdirectory(Vendor)
+
+add_executable(AtomicEditor ${EXE_TYPE} ${SOURCE_FILES})
+
+target_link_libraries(AtomicEditor ${ATOMIC_LINK_LIBRARIES} Poco)
+
+if (APPLE)
+    set (TARGET_PROPERTIES MACOSX_BUNDLE_INFO_PLIST MacOSXBundleInfo.plist.template)
+    target_link_libraries(AtomicEditor curl)
+else()
+
+    target_link_libraries(AtomicEditor libcurl Iphlpapi Wldap32)
+
+endif()
+
+if (TARGET_PROPERTIES)
+    set_target_properties (AtomicEditor PROPERTIES ${TARGET_PROPERTIES})
+endif ()

+ 3 - 0
AtomicEditor/EditorApplicationData/Deployment/Android/assets/.gitignore

@@ -0,0 +1,3 @@
+# Ignore everything as it just contains symlinks or copied of files (Windows platform without MKLINK)
+*
+!.gitignore

+ 83 - 0
AtomicEditor/EditorApplicationData/Deployment/Android/build.xml

@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project name="Atomic" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var"
+            unless="sdk.dir"
+    />
+
+    <!--
+        Import per project custom build rules if present at the root of the project.
+        This is the place to put custom intermediary targets such as:
+            -pre-build
+            -pre-compile
+            -post-compile (This is typically used for code obfuscation.
+                           Compiled code location: ${out.classes.absolute.dir}
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
+            -post-package
+            -post-build
+            -pre-clean
+    -->
+    <import file="custom_rules.xml" optional="true" />
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>

BIN
AtomicEditor/EditorApplicationData/Deployment/Android/res/drawable-hdpi/icon.png


BIN
AtomicEditor/EditorApplicationData/Deployment/Android/res/drawable-ldpi/icon.png


BIN
AtomicEditor/EditorApplicationData/Deployment/Android/res/drawable-mdpi/icon.png


BIN
AtomicEditor/EditorApplicationData/Deployment/Android/res/drawable/logo_large.png


+ 25 - 0
AtomicEditor/EditorApplicationData/Deployment/Android/res/layout/samples_list.xml

@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical" >
+
+    <ImageView
+        android:id="@+id/imageView"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:src="@drawable/logo_large" />
+
+    <ListView
+        android:id="@android:id/list"
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
+        android:layout_weight="1" />
+
+    <TextView
+        android:id="@android:id/empty"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="No activities" />
+
+</LinearLayout>

+ 11 - 0
AtomicEditor/EditorApplicationData/Deployment/Android/res/layout/samples_list_text_view.xml

@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@android:id/text1"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:gravity="center_vertical"
+    android:paddingBottom="14dp"
+    android:paddingTop="14dp"
+    android:paddingLeft="14dp"
+    android:paddingRight="14dp"
+    android:textSize="22sp" />

+ 0 - 0
AtomicEditor/EditorApplicationData/Deployment/Android/res/values/.gitkeep


+ 1112 - 0
AtomicEditor/EditorApplicationData/Deployment/Android/src/org/libsdl/app/SDLActivity.java

@@ -0,0 +1,1112 @@
+// Modified by Lasse Oorni and Yao Wei Tjong for Urho3D
+
+package org.libsdl.app;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import android.app.*;
+import android.content.*;
+import android.view.*;
+import android.view.inputmethod.BaseInputConnection;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputConnection;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AbsoluteLayout;
+import android.os.*;
+import android.util.Log;
+import android.graphics.*;
+import android.media.*;
+import android.hardware.*;
+
+
+/**
+    SDL Activity
+*/
+public class SDLActivity extends Activity {
+    private static final String TAG = "SDL";
+
+    // Keep track of the paused state
+    public static boolean mIsPaused, mIsSurfaceReady, mHasFocus;
+    public static boolean mExitCalledFromJava;
+
+    // Main components
+    protected static SDLActivity mSingleton;
+    protected static SDLSurface mSurface;
+    protected static View mTextEdit;
+    protected static ViewGroup mLayout;
+    protected static SDLJoystickHandler mJoystickHandler;
+
+    // This is what SDL runs in. It invokes SDL_main(), eventually
+    protected static Thread mSDLThread;
+    
+    // Audio
+    protected static AudioTrack mAudioTrack;
+
+    // Atomic: flag to load the .so and a new method load them
+    private static boolean mIsSharedLibraryLoaded = false;
+
+    protected boolean onLoadLibrary(ArrayList<String> libraryNames) {
+        for (final String name : libraryNames) {
+            System.loadLibrary(name);
+        }
+        return true;
+    }
+    
+    
+    public static void initialize() {
+        // The static nature of the singleton and Android quirkyness force us to initialize everything here
+        // Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values
+        mSingleton = null;
+        mSurface = null;
+        mTextEdit = null;
+        mLayout = null;
+        mJoystickHandler = null;
+        mSDLThread = null;
+        mAudioTrack = null;
+        mExitCalledFromJava = false;
+        mIsPaused = false;
+        mIsSurfaceReady = false;
+        mHasFocus = true;
+    }
+
+    // Setup
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        Log.v("SDL", "onCreate():" + mSingleton);
+        super.onCreate(savedInstanceState);
+        
+        SDLActivity.initialize();
+        // So we can call stuff from static callbacks
+        mSingleton = this;
+        
+        // Atomic: auto load all the shared libraries available in the library path
+        String libraryPath = getApplicationInfo().nativeLibraryDir;
+        //Log.v(TAG, "library path: " + libraryPath);
+        if (!mIsSharedLibraryLoaded) {
+            File[] files = new File(libraryPath).listFiles(new FilenameFilter() {
+                @Override
+                public boolean accept(File dir, String filename) {
+                    // Only list libraries, i.e. exclude gdbserver when it presents
+                    return filename.matches("^lib.*\\.so$");
+                }
+            });
+            Arrays.sort(files, new Comparator<File>() {
+                @Override
+                public int compare(File lhs, File rhs) {
+                    return Long.valueOf(lhs.lastModified()).compareTo(rhs.lastModified());
+                }
+            });
+            ArrayList<String> libraryNames = new ArrayList<String>(files.length);
+            for (final File libraryFilename : files) {
+                String name = libraryFilename.getName().replaceAll("^lib(.*)\\.so$", "$1");
+                //Log.v(TAG, "library name: " + name);
+                libraryNames.add(name);
+            }
+            if (onLoadLibrary(libraryNames))
+                mIsSharedLibraryLoaded = true;
+        }
+
+        // Set up the surface
+        mSurface = new SDLSurface(getApplication());
+        
+        if(Build.VERSION.SDK_INT >= 12) {
+            mJoystickHandler = new SDLJoystickHandler_API12();
+        }
+        else {
+            mJoystickHandler = new SDLJoystickHandler();
+        }
+
+        mLayout = new AbsoluteLayout(this);
+        mLayout.addView(mSurface);
+
+        setContentView(mLayout);
+    }
+
+    // Events
+    @Override
+    protected void onPause() {
+        Log.v("SDL", "onPause()");
+        super.onPause();
+        SDLActivity.handlePause();
+    }
+
+    @Override
+    protected void onResume() {
+        Log.v("SDL", "onResume()");
+        super.onResume();
+        SDLActivity.handleResume();
+    }
+
+
+    @Override
+    public void onWindowFocusChanged(boolean hasFocus) {
+        super.onWindowFocusChanged(hasFocus);
+        Log.v("SDL", "onWindowFocusChanged(): " + hasFocus);
+
+        SDLActivity.mHasFocus = hasFocus;
+        if (hasFocus) {
+            SDLActivity.handleResume();
+        }
+    }
+
+    @Override
+    public void onLowMemory() {
+        Log.v("SDL", "onLowMemory()");
+        super.onLowMemory();
+        SDLActivity.nativeLowMemory();
+    }
+
+    @Override
+    protected void onDestroy() {
+        Log.v("SDL", "onDestroy()");
+        // Send a quit message to the application
+        SDLActivity.mExitCalledFromJava = true;
+        // Atomic - Send a quit message to the application only when native library has been loaded
+        if (mIsSharedLibraryLoaded)
+            SDLActivity.nativeQuit();
+
+        // Now wait for the SDL thread to quit
+        if (SDLActivity.mSDLThread != null) {
+            try {
+                SDLActivity.mSDLThread.join();
+            } catch(Exception e) {
+                Log.v("SDL", "Problem stopping thread: " + e);
+            }
+            SDLActivity.mSDLThread = null;
+
+            //Log.v("SDL", "Finished waiting for SDL thread");
+        }
+            
+        super.onDestroy();
+        // Reset everything in case the user re opens the app
+        SDLActivity.initialize();
+    }
+
+    @Override
+    public boolean dispatchKeyEvent(KeyEvent event) {
+        int keyCode = event.getKeyCode();
+        // Ignore certain special keys so they're handled by Android
+        // Atomic: also ignore the Home key
+        if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN ||
+            keyCode == KeyEvent.KEYCODE_VOLUME_UP ||
+            keyCode == KeyEvent.KEYCODE_HOME ||
+            keyCode == KeyEvent.KEYCODE_CAMERA ||
+            keyCode == 168 || /* API 11: KeyEvent.KEYCODE_ZOOM_IN */
+            keyCode == 169 /* API 11: KeyEvent.KEYCODE_ZOOM_OUT */
+            ) {
+            return false;
+        }
+        return super.dispatchKeyEvent(event);
+    }
+
+    /** Called by onPause or surfaceDestroyed. Even if surfaceDestroyed
+     *  is the first to be called, mIsSurfaceReady should still be set
+     *  to 'true' during the call to onPause (in a usual scenario).
+     */
+    public static void handlePause() {
+        if (!SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady) {
+            SDLActivity.mIsPaused = true;
+            SDLActivity.nativePause();
+            mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, false);
+        }
+    }
+
+    /** Called by onResume or surfaceCreated. An actual resume should be done only when the surface is ready.
+     * Note: Some Android variants may send multiple surfaceChanged events, so we don't need to resume
+     * every time we get one of those events, only if it comes after surfaceDestroyed
+     */
+    public static void handleResume() {
+        if (SDLActivity.mIsPaused && SDLActivity.mIsSurfaceReady && SDLActivity.mHasFocus) {
+            SDLActivity.mIsPaused = false;
+            SDLActivity.nativeResume();
+            mSurface.enableSensor(Sensor.TYPE_ACCELEROMETER, true);
+        }
+    }
+        
+    /* The native thread has finished */
+    public static void handleNativeExit() {
+        SDLActivity.mSDLThread = null;
+        mSingleton.finish();
+    }
+
+
+    // Messages from the SDLMain thread
+    static final int COMMAND_CHANGE_TITLE = 1;
+    static final int COMMAND_UNUSED = 2;
+    static final int COMMAND_TEXTEDIT_HIDE = 3;
+
+    protected static final int COMMAND_USER = 0x8000;
+
+    /**
+     * This method is called by SDL if SDL did not handle a message itself.
+     * This happens if a received message contains an unsupported command.
+     * Method can be overwritten to handle Messages in a different class.
+     * @param command the command of the message.
+     * @param param the parameter of the message. May be null.
+     * @return if the message was handled in overridden method.
+     */
+    protected boolean onUnhandledMessage(int command, Object param) {
+        return false;
+    }
+
+    /**
+     * A Handler class for Messages from native SDL applications.
+     * It uses current Activities as target (e.g. for the title).
+     * static to prevent implicit references to enclosing object.
+     */
+    protected static class SDLCommandHandler extends Handler {
+        @Override
+        public void handleMessage(Message msg) {
+            Context context = getContext();
+            if (context == null) {
+                Log.e(TAG, "error handling message, getContext() returned null");
+                return;
+            }
+            switch (msg.arg1) {
+            case COMMAND_CHANGE_TITLE:
+                if (context instanceof Activity) {
+                    ((Activity) context).setTitle((String)msg.obj);
+                } else {
+                    Log.e(TAG, "error handling message, getContext() returned no Activity");
+                }
+                break;
+            case COMMAND_TEXTEDIT_HIDE:
+                if (mTextEdit != null) {
+                    mTextEdit.setVisibility(View.GONE);
+
+                    InputMethodManager imm = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
+                    imm.hideSoftInputFromWindow(mTextEdit.getWindowToken(), 0);
+                }
+                break;
+
+            default:
+                if ((context instanceof SDLActivity) && !((SDLActivity) context).onUnhandledMessage(msg.arg1, msg.obj)) {
+                    Log.e(TAG, "error handling message, command is " + msg.arg1);
+                }
+            }
+        }
+    }
+
+    // Handler for the messages
+    Handler commandHandler = new SDLCommandHandler();
+
+    // Send a message from the SDLMain thread
+    boolean sendCommand(int command, Object data) {
+        Message msg = commandHandler.obtainMessage();
+        msg.arg1 = command;
+        msg.obj = data;
+        return commandHandler.sendMessage(msg);
+    }
+
+    // C functions we call
+    // Atomic: added parameter
+    public static native void nativeInit(String filesDir);
+    public static native void nativeLowMemory();
+    public static native void nativeQuit();
+    public static native void nativePause();
+    public static native void nativeResume();
+    public static native void onNativeResize(int x, int y, int format);
+    public static native int onNativePadDown(int device_id, int keycode);
+    public static native int onNativePadUp(int device_id, int keycode);
+    public static native void onNativeJoy(int device_id, int axis,
+                                          float value);
+    public static native void onNativeHat(int device_id, int hat_id,
+                                          int x, int y);
+    public static native void onNativeKeyDown(int keycode);
+    public static native void onNativeKeyUp(int keycode);
+    public static native void onNativeKeyboardFocusLost();
+    public static native void onNativeTouch(int touchDevId, int pointerFingerId,
+                                            int action, float x, 
+                                            float y, float p);
+    public static native void onNativeAccel(float x, float y, float z);
+    public static native void onNativeSurfaceChanged();
+    public static native void onNativeSurfaceDestroyed();
+    public static native void nativeFlipBuffers();
+    public static native int nativeAddJoystick(int device_id, String name, 
+                                               int is_accelerometer, int nbuttons, 
+                                               int naxes, int nhats, int nballs);
+    public static native int nativeRemoveJoystick(int device_id);
+
+    public static void flipBuffers() {
+        SDLActivity.nativeFlipBuffers();
+    }
+
+    public static boolean setActivityTitle(String title) {
+        // Called from SDLMain() thread and can't directly affect the view
+        return mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
+    }
+
+    public static boolean sendMessage(int command, int param) {
+        return mSingleton.sendCommand(command, Integer.valueOf(param));
+    }
+
+    public static Context getContext() {
+        return mSingleton;
+    }
+
+    /**
+     * @return result of getSystemService(name) but executed on UI thread.
+     */
+    public Object getSystemServiceFromUiThread(final String name) {
+        final Object lock = new Object();
+        final Object[] results = new Object[2]; // array for writable variables
+        synchronized (lock) {
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (lock) {
+                        results[0] = getSystemService(name);
+                        results[1] = Boolean.TRUE;
+                        lock.notify();
+                    }
+                }
+            });
+            if (results[1] == null) {
+                try {
+                    lock.wait();
+                } catch (InterruptedException ex) {
+                    ex.printStackTrace();
+                }
+            }
+        }
+        return results[0];
+    }
+
+    static class ShowTextInputTask implements Runnable {
+        /*
+         * This is used to regulate the pan&scan method to have some offset from
+         * the bottom edge of the input region and the top edge of an input
+         * method (soft keyboard)
+         */
+        static final int HEIGHT_PADDING = 15;
+
+        public int x, y, w, h;
+
+        public ShowTextInputTask(int x, int y, int w, int h) {
+            this.x = x;
+            this.y = y;
+            this.w = w;
+            this.h = h;
+        }
+
+        @Override
+        public void run() {
+            AbsoluteLayout.LayoutParams params = new AbsoluteLayout.LayoutParams(
+                    w, h + HEIGHT_PADDING, x, y);
+
+            if (mTextEdit == null) {
+                mTextEdit = new DummyEdit(getContext());
+
+                mLayout.addView(mTextEdit, params);
+            } else {
+                mTextEdit.setLayoutParams(params);
+            }
+
+            mTextEdit.setVisibility(View.VISIBLE);
+            mTextEdit.requestFocus();
+
+            InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+            imm.showSoftInput(mTextEdit, 0);
+        }
+    }
+
+    public static boolean showTextInput(int x, int y, int w, int h) {
+        // Transfer the task to the main thread as a Runnable
+        return mSingleton.commandHandler.post(new ShowTextInputTask(x, y, w, h));
+    }
+            
+    public static Surface getNativeSurface() {
+        return SDLActivity.mSurface.getNativeSurface();
+    }
+
+    // Audio
+    public static int audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
+        int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
+        int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
+        int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
+        
+        Log.v("SDL", "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+        
+        // Let the user pick a larger buffer if they really want -- but ye
+        // gods they probably shouldn't, the minimums are horrifyingly high
+        // latency already
+        desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
+        
+        if (mAudioTrack == null) {
+            mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
+                    channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
+            
+            // Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
+            // Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
+            // Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
+            
+            if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
+                Log.e("SDL", "Failed during initialization of Audio Track");
+                mAudioTrack = null;
+                return -1;
+            }
+            
+            mAudioTrack.play();
+        }
+       
+        Log.v("SDL", "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+        
+        return 0;
+    }
+    
+    public static void audioWriteShortBuffer(short[] buffer) {
+        for (int i = 0; i < buffer.length; ) {
+            int result = mAudioTrack.write(buffer, i, buffer.length - i);
+            if (result > 0) {
+                i += result;
+            } else if (result == 0) {
+                try {
+                    Thread.sleep(1);
+                } catch(InterruptedException e) {
+                    // Nom nom
+                }
+            } else {
+                Log.w("SDL", "SDL audio: error return from write(short)");
+                return;
+            }
+        }
+    }
+    
+    public static void audioWriteByteBuffer(byte[] buffer) {
+        for (int i = 0; i < buffer.length; ) {
+            int result = mAudioTrack.write(buffer, i, buffer.length - i);
+            if (result > 0) {
+                i += result;
+            } else if (result == 0) {
+                try {
+                    Thread.sleep(1);
+                } catch(InterruptedException e) {
+                    // Nom nom
+                }
+            } else {
+                Log.w("SDL", "SDL audio: error return from write(byte)");
+                return;
+            }
+        }
+    }
+
+    public static void audioQuit() {
+        if (mAudioTrack != null) {
+            mAudioTrack.stop();
+            mAudioTrack = null;
+        }
+    }
+
+    // Input
+
+    /**
+     * @return an array which may be empty but is never null.
+     */
+    public static int[] inputGetInputDeviceIds(int sources) {
+        int[] ids = InputDevice.getDeviceIds();
+        int[] filtered = new int[ids.length];
+        int used = 0;
+        for (int i = 0; i < ids.length; ++i) {
+            InputDevice device = InputDevice.getDevice(ids[i]);
+            if ((device != null) && ((device.getSources() & sources) != 0)) {
+                filtered[used++] = device.getId();
+            }
+        }
+        return Arrays.copyOf(filtered, used);
+    }
+
+    // Atomic: add handler null check
+    // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
+    public static boolean handleJoystickMotionEvent(MotionEvent event) {
+        return mJoystickHandler != null && mJoystickHandler.handleMotionEvent(event); 
+    }
+    
+    public static void pollInputDevices() {
+        if (SDLActivity.mSDLThread != null && mJoystickHandler != null) {
+            mJoystickHandler.pollInputDevices();
+        }
+    }
+    
+}
+
+/**
+    Simple nativeInit() runnable
+*/
+class SDLMain implements Runnable {
+    @Override
+    public void run() {
+        // Runs SDL_main()
+        // Atomic: pass filesDir
+        SDLActivity.nativeInit(((Activity)SDLActivity.getContext()).getFilesDir().getAbsolutePath());
+        //Log.v("SDL", "SDL thread terminated");
+    }
+}
+
+
+/**
+    SDLSurface. This is what we draw on, so we need to know when it's created
+    in order to do anything useful. 
+
+    Because of this, that's where we set up the SDL thread
+*/
+class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 
+    View.OnKeyListener, View.OnTouchListener, SensorEventListener  {
+
+    // Sensors
+    protected static SensorManager mSensorManager;
+    protected static Display mDisplay;
+
+    // Keep track of the surface size to normalize touch events
+    protected static float mWidth, mHeight;
+
+    // Startup    
+    public SDLSurface(Context context) {
+        super(context);
+        getHolder().addCallback(this); 
+    
+        setFocusable(true);
+        setFocusableInTouchMode(true);
+        requestFocus();
+        setOnKeyListener(this); 
+        setOnTouchListener(this);   
+
+        mDisplay = ((WindowManager)context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
+        mSensorManager = (SensorManager)context.getSystemService(Context.SENSOR_SERVICE);
+        
+        if(Build.VERSION.SDK_INT >= 12) {
+            setOnGenericMotionListener(new SDLGenericMotionListener_API12());
+        }
+
+        // Some arbitrary defaults to avoid a potential division by zero
+        mWidth = 1.0f;
+        mHeight = 1.0f;
+    }
+    
+    public Surface getNativeSurface() {
+        return getHolder().getSurface();
+    }
+
+    // Called when we have a valid drawing surface
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+        Log.v("SDL", "surfaceCreated()");
+        holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
+    }
+
+    // Called when we lose the surface
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+        Log.v("SDL", "surfaceDestroyed()");
+        // Call this *before* setting mIsSurfaceReady to 'false'
+        SDLActivity.handlePause();
+        SDLActivity.mIsSurfaceReady = false;
+        SDLActivity.onNativeSurfaceDestroyed();
+    }
+
+    // Called when the surface is resized
+    @Override
+    public void surfaceChanged(SurfaceHolder holder,
+                               int format, int width, int height) {
+        Log.v("SDL", "surfaceChanged()");
+
+        int sdlFormat = 0x15151002; // SDL_PIXELFORMAT_RGB565 by default
+        switch (format) {
+        case PixelFormat.A_8:
+            Log.v("SDL", "pixel format A_8");
+            break;
+        case PixelFormat.LA_88:
+            Log.v("SDL", "pixel format LA_88");
+            break;
+        case PixelFormat.L_8:
+            Log.v("SDL", "pixel format L_8");
+            break;
+        case PixelFormat.RGBA_4444:
+            Log.v("SDL", "pixel format RGBA_4444");
+            sdlFormat = 0x15421002; // SDL_PIXELFORMAT_RGBA4444
+            break;
+        case PixelFormat.RGBA_5551:
+            Log.v("SDL", "pixel format RGBA_5551");
+            sdlFormat = 0x15441002; // SDL_PIXELFORMAT_RGBA5551
+            break;
+        case PixelFormat.RGBA_8888:
+            Log.v("SDL", "pixel format RGBA_8888");
+            sdlFormat = 0x16462004; // SDL_PIXELFORMAT_RGBA8888
+            break;
+        case PixelFormat.RGBX_8888:
+            Log.v("SDL", "pixel format RGBX_8888");
+            sdlFormat = 0x16261804; // SDL_PIXELFORMAT_RGBX8888
+            break;
+        case PixelFormat.RGB_332:
+            Log.v("SDL", "pixel format RGB_332");
+            sdlFormat = 0x14110801; // SDL_PIXELFORMAT_RGB332
+            break;
+        case PixelFormat.RGB_565:
+            Log.v("SDL", "pixel format RGB_565");
+            sdlFormat = 0x15151002; // SDL_PIXELFORMAT_RGB565
+            break;
+        case PixelFormat.RGB_888:
+            Log.v("SDL", "pixel format RGB_888");
+            // Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
+            sdlFormat = 0x16161804; // SDL_PIXELFORMAT_RGB888
+            break;
+        default:
+            Log.v("SDL", "pixel format unknown " + format);
+            break;
+        }
+
+        mWidth = width;
+        mHeight = height;
+        SDLActivity.onNativeResize(width, height, sdlFormat);
+        Log.v("SDL", "Window size:" + width + "x"+height);
+
+        // Set mIsSurfaceReady to 'true' *before* making a call to handleResume
+        SDLActivity.mIsSurfaceReady = true;
+        SDLActivity.onNativeSurfaceChanged();
+
+
+        if (SDLActivity.mSDLThread == null) {
+            // This is the entry point to the C app.
+            // Start up the C app thread and enable sensor input for the first time
+
+            SDLActivity.mSDLThread = new Thread(new SDLMain(), "SDLThread");
+            enableSensor(Sensor.TYPE_ACCELEROMETER, true);
+            SDLActivity.mSDLThread.start();
+            
+            // Set up a listener thread to catch when the native thread ends
+            new Thread(new Runnable(){
+                @Override
+                public void run(){
+                    try {
+                        SDLActivity.mSDLThread.join();
+                    }
+                    catch(Exception e){}
+                    finally{ 
+                        // Native thread has finished
+                        if (! SDLActivity.mExitCalledFromJava) {
+                            SDLActivity.handleNativeExit();
+                        }
+                    }
+                }
+            }).start();
+        }
+    }
+
+    // unused
+    @Override
+    public void onDraw(Canvas canvas) {}
+
+
+    // Key events
+    @Override
+    public boolean onKey(View  v, int keyCode, KeyEvent event) {
+        // Dispatch the different events depending on where they come from
+        // Some SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
+        // So, we try to process them as DPAD or GAMEPAD events first, if that fails we try them as KEYBOARD
+        
+        if ( (event.getSource() & 0x00000401) != 0 || /* API 12: SOURCE_GAMEPAD */
+                   (event.getSource() & InputDevice.SOURCE_DPAD) != 0 ) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
+                    return true;
+                }
+            } else if (event.getAction() == KeyEvent.ACTION_UP) {
+                if (SDLActivity.onNativePadUp(event.getDeviceId(), keyCode) == 0) {
+                    return true;
+                }
+            }
+        }
+        
+        if( (event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                //Log.v("SDL", "key down: " + keyCode);
+                SDLActivity.onNativeKeyDown(keyCode);
+                return true;
+            }
+            else if (event.getAction() == KeyEvent.ACTION_UP) {
+                //Log.v("SDL", "key up: " + keyCode);
+                SDLActivity.onNativeKeyUp(keyCode);
+                return true;
+            }
+        }
+        
+        return false;
+    }
+
+    // Touch events
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        /* Ref: http://developer.android.com/training/gestures/multi.html */
+        final int touchDevId = event.getDeviceId();
+        final int pointerCount = event.getPointerCount();
+        int action = event.getActionMasked();
+        int pointerFingerId;
+        int i = -1;
+        float x,y,p;
+        
+        switch(action) {
+            case MotionEvent.ACTION_MOVE:
+                for (i = 0; i < pointerCount; i++) {
+                    pointerFingerId = event.getPointerId(i);
+                    x = event.getX(i) / mWidth;
+                    y = event.getY(i) / mHeight;
+                    p = event.getPressure(i);
+                    SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
+                }
+                break;
+            
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_DOWN:
+                // Primary pointer up/down, the index is always zero
+                i = 0;
+            case MotionEvent.ACTION_POINTER_UP:
+            case MotionEvent.ACTION_POINTER_DOWN:
+                // Non primary pointer up/down
+                if (i == -1) {
+                    i = event.getActionIndex();
+                }
+                
+                pointerFingerId = event.getPointerId(i);
+                x = event.getX(i) / mWidth;
+                y = event.getY(i) / mHeight;
+                p = event.getPressure(i);
+                SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
+                break;
+            
+            default:
+                break;
+        }
+
+        return true;
+   } 
+
+    // Sensor events
+    public void enableSensor(int sensortype, boolean enabled) {
+        // TODO: This uses getDefaultSensor - what if we have >1 accels?
+        if (enabled) {
+            mSensorManager.registerListener(this, 
+                            mSensorManager.getDefaultSensor(sensortype), 
+                            SensorManager.SENSOR_DELAY_GAME, null);
+        } else {
+            mSensorManager.unregisterListener(this, 
+                            mSensorManager.getDefaultSensor(sensortype));
+        }
+    }
+    
+    @Override
+    public void onAccuracyChanged(Sensor sensor, int accuracy) {
+        // TODO
+    }
+
+    @Override
+    public void onSensorChanged(SensorEvent event) {
+        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
+            float x, y;
+            switch (mDisplay.getRotation()) {
+                case Surface.ROTATION_90:
+                    x = -event.values[1];
+                    y = event.values[0];
+                    break;
+                case Surface.ROTATION_270:
+                    x = event.values[1];
+                    y = -event.values[0];
+                    break;
+                case Surface.ROTATION_180:
+                    // Atomic: fix SDL copy-paste error
+                    x = -event.values[0];
+                    y = -event.values[1];
+                    break;
+                default:
+                    x = event.values[0];
+                    y = event.values[1];
+                    break;
+            }
+            SDLActivity.onNativeAccel(-x / SensorManager.GRAVITY_EARTH,
+                                      y / SensorManager.GRAVITY_EARTH,
+                                      event.values[2] / SensorManager.GRAVITY_EARTH - 1);
+        }
+    }    
+}
+
+/* This is a fake invisible editor view that receives the input and defines the
+ * pan&scan region
+ */
+class DummyEdit extends View implements View.OnKeyListener {
+    InputConnection ic;
+
+    public DummyEdit(Context context) {
+        super(context);
+        setFocusableInTouchMode(true);
+        setFocusable(true);
+        setOnKeyListener(this);
+    }
+
+    @Override
+    public boolean onCheckIsTextEditor() {
+        return true;
+    }
+
+    @Override
+    public boolean onKey(View v, int keyCode, KeyEvent event) {
+
+        // This handles the hardware keyboard input
+        if (event.isPrintingKey()) {
+            if (event.getAction() == KeyEvent.ACTION_DOWN) {
+                ic.commitText(String.valueOf((char) event.getUnicodeChar()), 1);
+            }
+            return true;
+        }
+
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            SDLActivity.onNativeKeyDown(keyCode);
+            return true;
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+            SDLActivity.onNativeKeyUp(keyCode);
+            return true;
+        }
+
+        return false;
+    }
+        
+    //
+    @Override
+    public boolean onKeyPreIme (int keyCode, KeyEvent event) {
+        // As seen on StackOverflow: http://stackoverflow.com/questions/7634346/keyboard-hide-event
+        // FIXME: Discussion at http://bugzilla.libsdl.org/show_bug.cgi?id=1639
+        // FIXME: This is not a 100% effective solution to the problem of detecting if the keyboard is showing or not
+        // FIXME: A more effective solution would be to change our Layout from AbsoluteLayout to Relative or Linear
+        // FIXME: And determine the keyboard presence doing this: http://stackoverflow.com/questions/2150078/how-to-check-visibility-of-software-keyboard-in-android
+        // FIXME: An even more effective way would be if Android provided this out of the box, but where would the fun be in that :)
+        if (event.getAction()==KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_BACK) {
+            if (SDLActivity.mTextEdit != null && SDLActivity.mTextEdit.getVisibility() == View.VISIBLE) {
+                SDLActivity.onNativeKeyboardFocusLost();
+            }
+        }
+        return super.onKeyPreIme(keyCode, event);
+    }
+
+    @Override
+    public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+        ic = new SDLInputConnection(this, true);
+
+        outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
+                | 33554432 /* API 11: EditorInfo.IME_FLAG_NO_FULLSCREEN */;
+
+        return ic;
+    }
+}
+
+class SDLInputConnection extends BaseInputConnection {
+
+    public SDLInputConnection(View targetView, boolean fullEditor) {
+        super(targetView, fullEditor);
+
+    }
+
+    @Override
+    public boolean sendKeyEvent(KeyEvent event) {
+
+        /*
+         * This handles the keycodes from soft keyboard (and IME-translated
+         * input from hardkeyboard)
+         */
+        int keyCode = event.getKeyCode();
+        if (event.getAction() == KeyEvent.ACTION_DOWN) {
+            if (event.isPrintingKey()) {
+                commitText(String.valueOf((char) event.getUnicodeChar()), 1);
+            }
+            SDLActivity.onNativeKeyDown(keyCode);
+            return true;
+        } else if (event.getAction() == KeyEvent.ACTION_UP) {
+
+            SDLActivity.onNativeKeyUp(keyCode);
+            return true;
+        }
+        return super.sendKeyEvent(event);
+    }
+
+    @Override
+    public boolean commitText(CharSequence text, int newCursorPosition) {
+
+        nativeCommitText(text.toString(), newCursorPosition);
+
+        return super.commitText(text, newCursorPosition);
+    }
+
+    @Override
+    public boolean setComposingText(CharSequence text, int newCursorPosition) {
+
+        nativeSetComposingText(text.toString(), newCursorPosition);
+
+        return super.setComposingText(text, newCursorPosition);
+    }
+
+    public native void nativeCommitText(String text, int newCursorPosition);
+
+    public native void nativeSetComposingText(String text, int newCursorPosition);
+
+    @Override
+    public boolean deleteSurroundingText(int beforeLength, int afterLength) {       
+        // Workaround to capture backspace key. Ref: http://stackoverflow.com/questions/14560344/android-backspace-in-webview-baseinputconnection
+        if (beforeLength == 1 && afterLength == 0) {
+            // backspace
+            return super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DEL))
+                && super.sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DEL));
+        }
+
+        return super.deleteSurroundingText(beforeLength, afterLength);
+    }
+}
+
+/* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */
+class SDLJoystickHandler {
+    
+    public boolean handleMotionEvent(MotionEvent event) {
+        return false;
+    }
+    
+    public void pollInputDevices() {
+    }
+}
+
+/* Actual joystick functionality available for API >= 12 devices */
+class SDLJoystickHandler_API12 extends SDLJoystickHandler {
+  
+    class SDLJoystick {
+        public int device_id;
+        public String name;
+        public ArrayList<InputDevice.MotionRange> axes;
+        public ArrayList<InputDevice.MotionRange> hats;
+    }
+    class RangeComparator implements Comparator<InputDevice.MotionRange>
+    {
+        @Override
+        public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
+            return arg0.getAxis() - arg1.getAxis();
+        }
+    }
+    
+    private ArrayList<SDLJoystick> mJoysticks;
+    
+    public SDLJoystickHandler_API12() {
+       
+        mJoysticks = new ArrayList<SDLJoystick>();
+    }
+
+    @Override
+    public void pollInputDevices() {
+        int[] deviceIds = InputDevice.getDeviceIds();
+        // It helps processing the device ids in reverse order
+        // For example, in the case of the XBox 360 wireless dongle,
+        // so the first controller seen by SDL matches what the receiver
+        // considers to be the first controller
+        
+        for(int i=deviceIds.length-1; i>-1; i--) {
+            SDLJoystick joystick = getJoystick(deviceIds[i]);
+            if (joystick == null) {
+                joystick = new SDLJoystick();
+                InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
+                if( (joystickDevice.getSources() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+                    joystick.device_id = deviceIds[i];
+                    joystick.name = joystickDevice.getName();
+                    joystick.axes = new ArrayList<InputDevice.MotionRange>();
+                    joystick.hats = new ArrayList<InputDevice.MotionRange>();
+                    
+                    List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
+                    Collections.sort(ranges, new RangeComparator());
+                    for (InputDevice.MotionRange range : ranges ) {
+                        if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 ) {
+                            if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
+                                range.getAxis() == MotionEvent.AXIS_HAT_Y) {
+                                joystick.hats.add(range);
+                            }
+                            else {
+                                joystick.axes.add(range);
+                            }
+                        }
+                    }
+                    
+                    mJoysticks.add(joystick);
+                    SDLActivity.nativeAddJoystick(joystick.device_id, joystick.name, 0, -1, 
+                                                  joystick.axes.size(), joystick.hats.size()/2, 0);
+                }
+            }
+        }
+        
+        /* Check removed devices */
+        ArrayList<Integer> removedDevices = new ArrayList<Integer>();
+        for(int i=0; i < mJoysticks.size(); i++) {
+            int device_id = mJoysticks.get(i).device_id;
+            int j;
+            for (j=0; j < deviceIds.length; j++) {
+                if (device_id == deviceIds[j]) break;
+            }
+            if (j == deviceIds.length) {
+                removedDevices.add(device_id);
+            }
+        }
+            
+        for(int i=0; i < removedDevices.size(); i++) {
+            int device_id = removedDevices.get(i);
+            SDLActivity.nativeRemoveJoystick(device_id);
+            for (int j=0; j < mJoysticks.size(); j++) {
+                if (mJoysticks.get(j).device_id == device_id) {
+                    mJoysticks.remove(j);
+                    break;
+                }
+            }
+        }        
+    }
+    
+    protected SDLJoystick getJoystick(int device_id) {
+        for(int i=0; i < mJoysticks.size(); i++) {
+            if (mJoysticks.get(i).device_id == device_id) {
+                return mJoysticks.get(i);
+            }
+        }
+        return null;
+    }   
+    
+    @Override        
+    public boolean handleMotionEvent(MotionEvent event) {
+        if ( (event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
+            int actionPointerIndex = event.getActionIndex();
+            int action = event.getActionMasked();
+            switch(action) {
+                case MotionEvent.ACTION_MOVE:
+                    SDLJoystick joystick = getJoystick(event.getDeviceId());
+                    if ( joystick != null ) {
+                        for (int i = 0; i < joystick.axes.size(); i++) {
+                            InputDevice.MotionRange range = joystick.axes.get(i);
+                            /* Normalize the value to -1...1 */
+                            float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
+                            SDLActivity.onNativeJoy(joystick.device_id, i, value );
+                        }          
+                        for (int i = 0; i < joystick.hats.size(); i+=2) {
+                            int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
+                            int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
+                            SDLActivity.onNativeHat(joystick.device_id, i/2, hatX, hatY );
+                        }
+                    }
+                    break;
+                default:
+                    break;
+            }
+        }
+        return true;
+    }            
+}
+
+class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
+    // Generic Motion (mouse hover, joystick...) events go here
+    // We only have joysticks yet
+    @Override
+    public boolean onGenericMotion(View v, MotionEvent event) {
+        return SDLActivity.handleJoystickMotionEvent(event);
+    }
+}

+ 0 - 0
AtomicEditor/EditorApplicationData/Deployment/MacOS/.gitkeep


+ 43 - 0
AtomicEditor/EditorApplicationData/Deployment/MacOS/AtomicPlayer.app/Contents/Info.plist

@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+    <key>CFBundleDevelopmentRegion</key>
+    <string>English</string>
+    <key>CFBundleExecutable</key>
+    <string>AtomicPlayer</string>
+    <key>CFBundleGetInfoString</key>
+    <string></string>
+    <key>CFBundleIconFile</key>
+    <string>UrhoIcon</string>
+    <key>CFBundleIdentifier</key>
+    <string>com.thunderbeastgames.atomicplayer</string>
+    <key>CFBundleInfoDictionaryVersion</key>
+    <string>6.0</string>
+    <key>CFBundleLongVersionString</key>
+    <string>1.32.400</string>
+    <key>CFBundleName</key>
+    <string>AtomicPlayer</string>
+    <key>CFBundlePackageType</key>
+    <string>APPL</string>
+    <key>CFBundleShortVersionString</key>
+    <string>1.32.400</string>
+    <key>CFBundleSignature</key>
+    <string>????</string>
+    <key>CFBundleVersion</key>
+    <string>1.32.400</string>
+    <key>CFBundleIconFile</key>
+    <string>Atomic</string>    
+    <key>CSResourcesFileMapped</key>
+    <true/>
+    <key>LSRequiresCarbon</key>
+    <true/>
+    <key>NSHumanReadableCopyright</key>
+    <string>Copyright (c) 2015 THUNDERBEAST GAMES LLC</string>
+    <key>LSEnvironment</key>
+    <dict>
+        <key>URHO3D_PREFIX_PATH</key>
+        <string>../Resources</string>
+    </dict>
+</dict>
+</plist>

BIN
AtomicEditor/EditorApplicationData/Deployment/MacOS/AtomicPlayer.app/Contents/Resources/Atomic.icns


BIN
AtomicEditor/EditorApplicationData/ExampleInfo/CharacterAnimation3D.png


+ 41 - 0
AtomicEditor/EditorApplicationData/ExampleInfo/Examples.json

@@ -0,0 +1,41 @@
+{
+	"Examples" : [
+			{
+				"name": "Physics Platformer 2D",
+				"desc" : "Moving platforms, vines, and neat 2D lighting",
+				"screenshot" : "PhysicsPlatformer2D.png",
+				"folder" : "PhysicsPlatformer"
+			},
+			{
+				"name": "Roboman 3D",
+				"desc" : "A 3D physics example featuring Roboman!",
+				"screenshot" : "Roboman3D.png",
+				"folder" : "RoboMan3D"
+			},
+			{
+				"name": "SpaceGame",
+				"desc" : "A 2D Arcade Space Game",
+				"screenshot" : "SpaceGame.png",
+				"folder" : "SpaceGame"
+			},
+			{
+				"name": "Character Animation 3D",
+				"desc" : "Example of controlling a skeletally animated character",
+				"screenshot" : "CharacterAnimation3D.png",
+				"folder" : "CharacterAnimation3D"
+			},
+			{
+				"name": "Light 2D",
+				"desc" : "An example of realtime 2D lights with shadows",
+				"screenshot" : "Light2D.png",
+				"folder" : "Light2DExample"
+			},
+			{
+				"name": "UI Example",
+				"desc" : "A basic UI example showing responding to a click",
+				"screenshot" : "UIExample.png",
+				"folder" : "UIExample"
+			}
+
+	] 
+}

BIN
AtomicEditor/EditorApplicationData/ExampleInfo/Light2D.png


BIN
AtomicEditor/EditorApplicationData/ExampleInfo/PhysicsPlatformer2D.png


BIN
AtomicEditor/EditorApplicationData/ExampleInfo/Roboman3D.png


BIN
AtomicEditor/EditorApplicationData/ExampleInfo/SpaceGame.png


BIN
AtomicEditor/EditorApplicationData/ExampleInfo/UIExample.png


+ 0 - 0
AtomicEditor/EditorApplicationData/ProjectTemplates/EmptyProject/EmptyProject.atomic


+ 0 - 0
AtomicEditor/EditorApplicationData/ProjectTemplates/EmptyProject/Resources/Components/.gitkeep


+ 17 - 0
AtomicEditor/EditorApplicationData/ProjectTemplates/EmptyProject/Resources/Scripts/main.js

@@ -0,0 +1,17 @@
+
+// This script is the main entry point of the game
+require("AtomicGame");
+
+Atomic.game.init(start, update);
+
+// called at the start of play
+function start() {
+
+	var game = Atomic.game;
+}
+
+// called per frame
+function update(timeStep) {
+
+
+}

+ 0 - 0
AtomicEditor/EditorApplicationData/ProjectTemplates/Project2D/Project2D.atomic


+ 16 - 0
AtomicEditor/EditorApplicationData/ProjectTemplates/Project2D/Resources/Components/Star.js

@@ -0,0 +1,16 @@
+var game = Atomic.game;
+var node = self.node;
+
+function start() {
+
+	var sprite2D = node.createComponent("StaticSprite2D");
+	sprite2D.sprite = game.getSprite2D("Sprites/star.png");
+	sprite2D.blendMode = Atomic.BLEND_ALPHA;
+	
+}
+
+function update(timeStep) {	
+
+	node.roll(timeStep * 100);
+
+}

+ 25 - 0
AtomicEditor/EditorApplicationData/ProjectTemplates/Project2D/Resources/Scripts/main.js

@@ -0,0 +1,25 @@
+
+// This script is the main entry point of the game
+require("AtomicGame");
+
+Atomic.game.init(start, update);
+
+
+// called at the start of play
+function start() {
+
+	var game = Atomic.game;
+
+	// create a 2D scene
+	game.createScene2D();
+
+    var spaceNode = game.scene.createChild("Star");
+    spaceNode.createJSComponent("Star");
+
+}
+
+// called per frame
+function update(timeStep) {
+
+
+}

BIN
AtomicEditor/EditorApplicationData/ProjectTemplates/Project2D/Resources/Sprites/star.png


+ 0 - 0
AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Project3D.atomic


+ 21 - 0
AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Resources/Components/Chest.js

@@ -0,0 +1,21 @@
+var game = Atomic.game;
+var node = self.node;
+
+function start() {
+
+    var cache = game.cache;
+
+    var model = node.createComponent("StaticModel");
+    model.setModel(cache.getResource("Model", "Models/Chest.mdl"));
+    model.setMaterial(cache.getResource("Material", "Materials/Chest.xml"));
+        
+    node.pitch(-90);    
+        
+}
+
+
+function update(timeStep) {
+
+   node.roll(timeStep * 75);
+
+}

+ 5 - 0
AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Resources/Materials/Chest.xml

@@ -0,0 +1,5 @@
+<material>
+    <technique name="Techniques/Diff.xml" quality="0" />
+    <texture unit="diffuse" name="Textures/chest.png" />
+    <parameter name="MatSpecColor" value="0.3 0.3 0.3 16" />
+</material>

BIN
AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Resources/Models/Chest.mdl


+ 46 - 0
AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Resources/Scripts/main.js

@@ -0,0 +1,46 @@
+
+// This script is the main entry point of the game
+
+require("AtomicGame");
+
+Atomic.game.init(start, update);
+
+
+// called at the start of play
+function start() {
+
+	var game = Atomic.game;
+
+	// create a 2D scene
+	game.createScene3D();
+
+	var scene = game.scene;
+
+	// zone
+	var zoneNode = scene.createChild("Zone")
+    var zone = zoneNode.createComponent("Zone");
+    zone.boundingBox = [-1000, -1000, -1000, 1000, 1000 , 1000];
+    zone.ambientColor = [0.35, 0.35, 0.35];
+    zone.fogColor = [0.1, 0.1, 0.1, 1.0];
+    zone.fogStart = 10;
+    zone.fogEnd = 100;
+
+    game.cameraNode.position = [0, 2.5, -6];
+    game.cameraNode.pitch(20);
+
+    var lightNode = scene.createChild("Directional Light");
+    lightNode.direction = [0.6, -1.0, 0.8];
+    var light = lightNode.createComponent("Light")
+    light.lightType = Atomic.LIGHT_DIRECTIONAL;
+
+	// create the game component
+	var node = game.scene.createChild("Chest");
+	node.createJSComponent("Chest");
+
+}
+
+// called per frame
+function update(timeStep) {
+
+
+}

BIN
AtomicEditor/EditorApplicationData/ProjectTemplates/Project3D/Resources/Textures/chest.png


+ 28 - 0
AtomicEditor/EditorResources/AtomicEditor/Modules/AtomicEditor.js

@@ -0,0 +1,28 @@
+
+var game = Atomic.game;
+
+function Editor() {
+
+	// default to the entire screen
+	this.viewport = {
+		left: 0,
+		top: 0,
+		right: game.graphics.width,
+		bottom: game.graphics.height
+	}
+
+}
+
+Editor.prototype.setViewport = function(left, top, right, bottom) {
+	
+	this.viewport.left = left;
+	this.viewport.top = top;
+	this.viewport.right = right;
+	this.viewport.bottom = bottom;
+
+}
+
+
+var editor = new Editor();
+
+Atomic.editor = exports.editor = editor;

BIN
AtomicEditor/EditorResources/AtomicEditor/editor/images/atomic_logo.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/images/newproject_2d.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/images/newproject_3d.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/images/newproject_empty.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/bg_tile.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/component.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/file.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/folder.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/folder_create.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/folder_delete.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/image_frame.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/item_separator_x.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/javascript.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_android.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_atomic_64.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_html5.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_ios.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_mac.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/logo_windows.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/magnifier.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/play.png


+ 104 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/skin/skin.tb.txt

@@ -0,0 +1,104 @@
+# Editor skin override (contains some additions for the atomic editor)
+elements
+	background
+		bitmap bg_tile.png
+		type Tile
+	background_solid
+		background-color #3b3b3b
+		padding 10
+	AEContainer
+		type StretchBox
+		bitmap window.png
+		cut 16
+		expand 12
+		padding 0
+	Folder
+		text-color #aaaaaa
+	Folder.selected
+		text-color #ffffff
+	Folder.icon: type: Image, bitmap: folder.png
+
+	ImageCaption
+		background-color #00000066
+	ImageFrame
+		overlays
+			element ImageFrame.overlay
+				state all
+	ImageFrame.overlay
+		bitmap image_frame.png
+		cut 22
+		expand 15
+
+	StarButton
+		overlays
+			element Star
+				condition: target: ancestors, property: skin, value: "StarCondition"
+
+
+	Star
+		bitmap star_gray.png
+		type Image
+		img-position-x 0
+		img-position-y 0
+		img-ofs-x -8
+		img-ofs-y -12
+		overrides
+			element Star.active
+				condition: target: parent, property: hover
+	Star.active
+		bitmap star_gold.png
+		type Image
+		img-position-x 0
+		img-position-y 0
+		img-ofs-x -10
+		img-ofs-y -14
+
+	LineNumberSelectList
+		background-color #23241f
+
+	ComponentBitmap
+		bitmap component.png
+
+	MagnifierBitmap
+		bitmap magnifier.png
+
+	JavascriptBitmap
+		bitmap javascript.png
+
+	FolderCreateBitmap
+		bitmap folder_create.png
+
+	FolderDeleteBitmap
+		bitmap folder_delete.png
+
+	FileBitmap
+		bitmap file.png
+
+	PlayButton
+		bitmap play.png
+
+	AESeparator
+		bitmap item_separator_x.png
+		type Stretch Image
+
+	LogoAndroid
+		bitmap logo_android.png
+
+	LogoHTML5
+		bitmap logo_html5.png
+
+	LogoIOS
+		bitmap logo_ios.png
+
+	LogoMac
+		bitmap logo_mac.png
+
+	LogoWindows
+		bitmap logo_windows.png
+
+	LogoAtomic64
+		bitmap logo_atomic_64.png
+
+	TextCode
+		background-color #23241f
+

BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/star_gold.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/star_gray.png


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/[email protected]


BIN
AtomicEditor/EditorResources/AtomicEditor/editor/skin/window.png


+ 6 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/about.tb.txt

@@ -0,0 +1,6 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBLayout: 
+		TBTextField: text: "About:"
+		TBTextField: text: "The Atomic Game Engine"
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBButton: text: OK, id: ok

+ 22 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/activation.tb.txt

@@ -0,0 +1,22 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout: distribution: gravity
+		TBTextField: text: "License Key:"
+			font: size:18
+		TBLayout: gravity: left right, distribution-position: right bottom
+			TBEditField: id: license_key, autofocus: 1
+				lp: min-width: 380
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout:
+		TBButton: text: Activate, id: activate
+			lp: min-width: 128, min-height: 64
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout:
+		TBButton: text: "Get Activation Key", id: get_key
+		TBButton: text: "Lost My Key", id: lost_key
+		TBButton: text: Quit, id: quit
+
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBTextField: text: "Please contact [email protected] with any product key issues"		
+		
+

+ 6 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/activationsuccess.tb.txt

@@ -0,0 +1,6 @@
+TBLayout: axis: y, distribution: gravity
+	TBTextField: text: "Activation Successful"
+		font: size:18
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBButton: text: OK, id: ok
+		lp: min-width: 128, min-height: 64

+ 12 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/build.tb.txt

@@ -0,0 +1,12 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBLayout: 
+		TBTextField: text: "OutputPath:"
+		TBTextField: id: build_path
+			lp: min-width: 280
+		TBButton: text: "Choose" id: choose_path
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout: 
+		TBButton: text: Build, id: build
+			TBSkinImage: skin: LogoAtomic64, id: current_platform_indicator
+				lp: height: 28, width: 28
+		TBButton: text: Cancel, id: cancel

+ 14 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/buildsettings.tb.txt

@@ -0,0 +1,14 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBLayout: position: top
+		TBLayout: id: platformcontainer, axis: y, position: left, gravity: top bottom
+			lp: min-width: 160
+		TBLayout: id: settingscontainer
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout: distribution: gravity
+		TBLayout: axis: y, position: left, gravity: top left
+			TBButton: text: "Set Current Platform", id: set_current_platform
+				TBSkinImage: skin: LogoAtomic64, id: current_platform_indicator
+					lp: height: 28, width: 28
+		TBLayout:
+			TBButton: text: Ok, id: ok
+			TBButton: text: Cancel, id: cancel

+ 42 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/buildsettings_android.tb.txt

@@ -0,0 +1,42 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout: distribution: gravity
+		TBTextField: text: "App Name:"
+		TBLayout: gravity: left right, distribution-position: right bottom
+			TBEditField: id: app_name, autofocus: 1
+				lp: min-width: 220
+	TBLayout: distribution: gravity
+		TBTextField: text: "App Package:"
+		TBLayout: gravity: left right, distribution-position: right bottom
+			TBEditField: id: app_package, autofocus: 1
+				lp: min-width: 220
+	TBLayout: distribution: gravity
+		TBTextField: text: "Company Name:"
+		TBLayout: gravity: left right, distribution-position: right bottom
+			TBEditField: id: company_name, autofocus: 1
+				lp: min-width: 220
+	TBLayout: distribution: gravity
+		TBTextField: text: "Product Name:"
+		TBLayout: gravity: left right, distribution-position: right bottom
+			TBEditField: id: product_name, autofocus: 1
+				lp: min-width: 220
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout: axis: y, position: left, distribution: gravity
+		TBTextField: text: "Android SDK Path:"
+		TBLayout: gravity: left right, distribution-position: right bottom
+			TBEditField: id: sdk_path, autofocus: 0
+				lp: min-width: 250
+			TBButton: text: "Choose" id: choose_sdk_path
+	TBLayout: axis: y, position: left, distribution: gravity
+		TBTextField: text: "Android API Level:"
+		TBLayout: gravity: left right, distribution-position: right bottom
+			TBSelectDropdown: id: sdk_target_select
+				lp: min-width: 250
+			TBButton: text: "Refresh" id: refresh_sdk_targets
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBTextField: text: "Icon:"
+	TBLayout: gravity: left right, distribution-position: right bottom
+		TBSkinImage: skin: LogoAtomic64
+	TBTextField: text: "Splash Screen:"
+	TBLayout: gravity: left right, distribution-position: right bottom
+		TBSkinImage: skin: LogoAtomic64

+ 29 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/buildsettings_windows.tb.txt

@@ -0,0 +1,29 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout: distribution: gravity
+		TBTextField: text: "App Name:"
+		TBLayout: gravity: left right, distribution-position: right bottom
+			TBEditField: id: component_name, autofocus: 1
+				lp: min-width: 220
+	TBLayout: distribution: gravity
+		TBTextField: text: "App Identifier:"
+		TBLayout: gravity: left right, distribution-position: right bottom
+			TBEditField: id: component_name, autofocus: 1
+				lp: min-width: 220
+	TBLayout: distribution: gravity
+		TBTextField: text: "Company Name:"
+		TBLayout: gravity: left right, distribution-position: right bottom
+			TBEditField: id: component_name, autofocus: 1
+				lp: min-width: 220
+	TBLayout: distribution: gravity
+		TBTextField: text: "Product Name:"
+		TBLayout: gravity: left right, distribution-position: right bottom
+			TBEditField: id: component_name, autofocus: 1
+				lp: min-width: 220
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBTextField: text: "Icon:"
+	TBLayout: gravity: left right, distribution-position: right bottom
+		TBSkinImage: skin: LogoAtomic64
+	TBTextField: text: "Splash Screen:"
+	TBLayout: gravity: left right, distribution-position: right bottom
+		TBSkinImage: skin: LogoAtomic64

+ 5 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/consolewidget.tb.txt

@@ -0,0 +1,5 @@
+TBLayout: distribution: gravity, axis: y
+	TBTextField: gravity: left, text-align: left
+		text Console
+	TBLayout: distribution: gravity, id: consolelayout
+

+ 4 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/errorswidget.tb.txt

@@ -0,0 +1,4 @@
+TBLayout: distribution: gravity, axis: y
+	TBTextField: gravity: left, text-align: left
+		text Errors
+	TBLayout: distribution: gravity, id: errorlayout

+ 22 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/findtextwidget.tb.txt

@@ -0,0 +1,22 @@
+definitions
+	findtextbutton		
+		lp: height: 28
+		skin TBButton.flat
+TBContainer: skin: AEContainer, gravity: left right, id: findcontainer
+	TBLayout: distribution: gravity, size: available
+		TBButton: gravity: left
+			@include definitions>findtextbutton
+			text Case
+		TBButton: : gravity: left
+			@include definitions>findtextbutton
+			text Word
+		TBButton: : gravity: left
+			@include definitions>findtextbutton
+			text Wrap
+		TBEditField: gravity: left right, text-align: left, id: findtextedit
+		TBButton: : gravity: right
+			@include definitions>findtextbutton
+			text Find
+		TBButton: : gravity: right
+			@include definitions>findtextbutton
+			text Find Next

+ 4 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/issueswidget.tb.txt

@@ -0,0 +1,4 @@
+TBLayout: distribution: gravity, axis: y
+	TBTextField: gravity: left, text-align: left
+		text Issues
+	TBLayout: distribution: gravity, id: issuelayout

+ 66 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/mainframe.tb.txt

@@ -0,0 +1,66 @@
+definitions
+	menubutton		
+		lp: height: 28
+		skin TBButton.flat
+TBLayout: distribution: gravity, axis: y
+	TBContainer: skin: AEContainer, gravity: all, id: mainframecontainer
+		TBLayout: distribution: gravity, axis: y		
+			TBLayout: distribution: gravity
+				TBContainer: skin: AEContainer, gravity: left right
+					TBLayout: distribution: gravity
+						TBButton
+							@include definitions>menubutton
+							text Atomic Editor
+							id menu atomic editor
+						TBButton
+							@include definitions>menubutton
+							text File
+							id menu file
+						TBButton
+							@include definitions>menubutton
+							text Project
+							id menu project
+						TBButton
+							@include definitions>menubutton
+							text Edit
+							id menu edit
+						TBButton
+							@include definitions>menubutton
+							text Resources
+							id menu resources
+						TBButton
+							@include definitions>menubutton
+							text Help
+							id menu help
+						TBLayout: gravity: left right
+							TBWidget
+			TBLayout: distribution: gravity, position: top
+				TBLayout: distribution: gravity, id: projectviewcontainer, gravity: top bottom
+				TBLayout: distribution: gravity, axis: y
+					TBLayout: gravity: left right, id: maintoolbarcontainer
+					TBSeparator: gravity: left right, skin: AESeparator
+					TBLayout: distribution: gravity, id: resourceviewcontainer
+					TBContainer: skin: AEContainer, gravity: left right bottom, id: consolecontainer
+						TBEditField: multiline: 1, styling: 1, gravity: left right, id: consoletext
+							text: "Hello World!"
+			TBLayout: distribution: gravity
+				TBContainer: skin: AEContainer, gravity: left right
+					TBLayout: distribution: gravity
+						TBLayout: distribution: gravity
+							TBLayout: axis: y, position: left, gravity: top left
+								TBSkinImage: skin: LogoAtomic64, id: current_platform_indicator
+									lp: height: 28, width:28
+						TBLayout: gravity: left right
+							TBWidget
+						TBButton
+							@include definitions>menubutton
+							text Errors
+							id menu errors
+						TBButton
+							@include definitions>menubutton
+							text Issues
+							id menu issues
+						TBButton
+							@include definitions>menubutton
+							text Console
+							id menu console

+ 9 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/maintoolbar.tb.txt

@@ -0,0 +1,9 @@
+definitions
+	menubutton		
+		lp: height: 28, width: 28
+		skin TBButton.flat
+TBLayout: distribution: gravity
+	TBButton 
+		@include definitions>menubutton
+		TBSkinImage: skin: PlayButton
+		id maintoolbar_play

+ 6 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/managelicense.tb.txt

@@ -0,0 +1,6 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBLayout: 
+		TBButton: id: "return_activation" text: "Return Activation"
+		TBTextField: text: "Return the activation on this computer"
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBButton: text: OK, id: ok

+ 13 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/newproject.tb.txt

@@ -0,0 +1,13 @@
+TBLayout: axis: y, position: left
+	TBTextField: text: "Please select project type:"
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout:
+		TBButton: id: project_2d
+			TBImageWidget: filename: "AtomicEditor/editor/images/newproject_2d.png"
+		TBButton: id: project_3d
+			TBImageWidget: filename: "AtomicEditor/editor/images/newproject_3d.png"
+		TBButton: id: project_empty
+			TBImageWidget: filename: "AtomicEditor/editor/images/newproject_empty.png"			
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout:
+		TBButton: text: Cancel, id: cancel

+ 10 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/platformsinfo.tb.txt

@@ -0,0 +1,10 @@
+TBLayout: axis: y, distribution: gravity
+	TBEditField: multiline: 1, styling: 1, gravity: all, id: info, readonly: 1
+		text: "There are no platform deployments available\n\n" \
+				"You will be able to preview gameplay in the Atomic Editor.\n" \
+				"A platform license is required to deploy apps.\n\n"
+		lp: min-width: 480, min-height: 100
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout:
+		TBButton: text: OK, id: ok
+		TBButton: text: Purchase, id: purchase

+ 2 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/playerwidget.tb.txt

@@ -0,0 +1,2 @@
+TBLayout: distribution: gravity, size: available, axis: y, id: playerlayout
+	TBContainer: gravity: all, id: playercontainer

+ 9 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/programoutput.tb.txt

@@ -0,0 +1,9 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBTextField: text: "Program Output:", id: program_name
+	TBEditField: multiline: 1, styling: 0, gravity: all, id: output, readonly: 1
+		lp: min-width: 640, min-height: 480
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout: 
+		TBButton: text: OK, id: ok
+		TBButton: text: Cancel, id: cancel
+		

+ 5 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/progressmodal.tb.txt

@@ -0,0 +1,5 @@
+TBLayout: axis: y, distribution: gravity
+	lp: min-width: 320, min-height: 240
+	TBTextField: id: message
+		font: size: 14
+	TBProgressSpinner: id: spinner, value: 1

+ 13 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/projectframe.tb.txt

@@ -0,0 +1,13 @@
+TBLayout: distribution: gravity, axis: y, id: projectframe
+	lp: min-width: 300
+	TBEditField
+		id filter
+		gravity all
+		placeholder @search
+		type search	
+	TBWidget: gravity: all
+		TBLayout: distribution: gravity, id: foldercontainer, gravity: all
+	TBScrollContainer: scroll-mode: y-auto, id: contentcontainerscroll
+		TBLayout: id: contentcontainer, axis: y, position: left
+	
+

+ 10 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/resourcecreatecomponent.tb.txt

@@ -0,0 +1,10 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBLayout: 
+		TBTextField: text: "Component Name:"
+		TBEditField: id: component_name, autofocus: 1
+			lp: min-width: 180
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout: 
+		TBButton: text: Create, id: create
+		TBButton: text: Cancel, id: cancel
+		

+ 10 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/resourcecreatescript.tb.txt

@@ -0,0 +1,10 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBLayout: 
+		TBTextField: text: "Script Name:"
+		TBEditField: id: script_name, autofocus: 1
+			lp: min-width: 180
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout: 
+		TBButton: text: Create, id: create
+		TBButton: text: Cancel, id: cancel
+		

+ 9 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/resourcedelete.tb.txt

@@ -0,0 +1,9 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBLayout: 
+		TBEditField: multiline: 1, readonly: 1, id: message
+			lp: min-width: 640
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout: 
+		TBButton: text: Delete, id: delete
+		TBButton: text: Cancel, id: cancel
+		

+ 2 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/resourceframe.tb.txt

@@ -0,0 +1,2 @@
+TBLayout: distribution: gravity, size: available, axis: y, id: resourcelayout
+	TBTabContainer: gravity: all, id: tabcontainer

+ 10 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/resourcenewfolder.tb.txt

@@ -0,0 +1,10 @@
+TBLayout: axis: y, distribution: gravity, position: left
+	TBLayout: 
+		TBTextField: text: "Folder Name:"
+		TBEditField: id: folder_name, autofocus: 1
+			lp: min-width: 180
+	TBSeparator: gravity: left right, skin: AESeparator
+	TBLayout: 
+		TBButton: text: Create, id: create
+		TBButton: text: Cancel, id: cancel
+		

+ 39 - 0
AtomicEditor/EditorResources/AtomicEditor/editor/ui/welcomeframe.tb.txt

@@ -0,0 +1,39 @@
+TBLayout: distribution: gravity, size: available, axis: y, id: welcomelayout, position: left
+	TBLayout: distribution: gravity, size: available
+		lp: max-height: 150
+		TBLayout: axis: y 
+			TBLayout: distribution: gravity
+				TBButton: id: open project
+					text Open Project
+				TBButton: id: new project
+					text New Project
+			TBLayout: distribution: gravity, axis: y, position: left
+				TBEditField: text: "<color #76D6FF>Recent Projects:</color>", styling: 1, readonly: 1, adapt-to-content: 1, skin: 0
+				TBSelectList: gravity: all, id: recentprojects
+	TBLayout: distribution: gravity, size: available
+		TBLayout: distribution: gravity, axis: y, position: left
+			TBEditField: text: "<color #76D6FF>Welcome:</color>", styling: 1, readonly: 1, adapt-to-content: 1, skin: 0
+			TBEditField: multiline: 1, styling: 1, gravity: all, id: welcome_text, readonly: 1, adapt-to-content: 0
+				font: size: 14
+				lp: max-width: 420, min-width: 420
+				text: "Welcome to the     <widget TBImageWidget: filename: 'AtomicEditor/editor/images/atomic_logo.png'>\n\n" \
+				"<color #D4FB79>First Steps</color>\n\n" \
+				"• Try out some of the example projects on the right.\n\n" \
+				"• You can also create a new project based on a 2D or 3D template.\n\n" \
+				"<color #D4FB79>Getting Started Videos</color>\n" \
+				"<widget TBButton: text: 'http://atomicgameengine.com/videos', skin: TBButton.link>\n\n" \
+				"<color #D4FB79>API Documentation</color>\n" \
+				"<widget TBButton: text: 'http://atomicgameengine.com/learn', skin: TBButton.link>\n\n" \
+				"<color #D4FB79>Forum</color>\n" \
+				"<widget TBButton: text: 'http://atomicgameengine.com/forum', skin: TBButton.link>\n\n" \
+				"<color #D4FB79>Atomic Game Engine on GitHub</color>\n" \
+				"<widget TBButton: text: 'https://github.com/AtomicGameEngine', skin: TBButton.link>\n\n"				
+		TBLayout: distribution: gravity, axis: y, spacing: 12
+			TBLayout: distribution: gravity, size: available
+				TBContainer: gravity: left right
+					TBLayout: distribution: gravity
+						TBEditField: text: "<color #76D6FF>More Examples:</color>", styling: 1, readonly: 1, adapt-to-content: 1, skin: 0
+						TBButton: text: "https://github.com/AtomicGameEngine/AtomicExamples", skin: TBButton.link
+						TBWidget: gravity: left right
+			TBScrollContainer: scroll-mode: auto
+				TBLayout: id: examples_layout, axis: y, spacing: 12

+ 99 - 0
AtomicEditor/EditorResources/AtomicEditor/javascript/AtomicEditor.js

@@ -0,0 +1,99 @@
+__atomic_acorn = require('acorn');
+__atomic_acorn_loose = require('acorn_loose');
+__atomic_beautify = require('beautify');
+
+function __atomic_parse_to_json(source) {
+
+	var start = new Date().getTime();
+		
+	var comments = [];
+
+	var ast = __atomic_acorn.parse( source, {
+    	// collect ranges for each node
+    	ranges: true,
+    	locations: true,
+    	onComment: comments,
+	});	
+
+	var end = new Date().getTime();
+	var time = end - start;	
+
+	// print('Acorn parse time: ' + time);
+
+	ast["comments"] = comments;
+
+	start = new Date().getTime();
+	ast = JSON.stringify(ast);
+	end = new Date().getTime();
+	time = end - start;	
+
+	// print('JSON.stringify time: ' + time);
+
+	return ast;
+
+}
+
+function __atomic_parse_to_json_loose(source) {
+
+	var start = new Date().getTime();
+		
+	var comments = [];
+
+	var ast = __atomic_acorn_loose.parse_dammit( source, {
+    	// collect ranges for each node
+    	ranges: true,
+    	locations: true,
+    	onComment: comments,
+	});	
+
+	var end = new Date().getTime();
+	var time = end - start;	
+
+	// print('Acorn parse time: ' + time);
+
+	ast["comments"] = comments;
+
+	start = new Date().getTime();
+	ast = JSON.stringify(ast);
+	end = new Date().getTime();
+	time = end - start;	
+
+	// print('JSON.stringify time: ' + time);
+
+	return ast;
+
+}
+
+
+function __atomic_parse_error_check(source) {
+		
+	
+	try {	
+
+		__atomic_acorn.parse( source, {
+	    	ranges: true,
+	    	locations: true,
+		});	
+
+	} catch(e) {
+
+        //if (!(e instanceof __atomic_acorn.SyntaxError)) throw e;
+
+        if (!(e instanceof SyntaxError))
+        	return false; // rethrow?
+
+        return e;
+
+    }
+
+
+	return false;
+
+}
+
+// TODO: options
+function __atomic_js_beautify(source) {
+
+	return __atomic_beautify.js_beautify(source);
+
+}

File diff suppressed because it is too large
+ 541 - 0
AtomicEditor/EditorResources/AtomicEditor/javascript/modules/acorn.js


+ 1167 - 0
AtomicEditor/EditorResources/AtomicEditor/javascript/modules/acorn_loose.js

@@ -0,0 +1,1167 @@
+// Acorn: Loose parser
+//
+// This module provides an alternative parser (`parse_dammit`) that
+// exposes that same interface as `parse`, but will try to parse
+// anything as JavaScript, repairing syntax error the best it can.
+// There are circumstances in which it will raise an error and give
+// up, but they are very rare. The resulting AST will be a mostly
+// valid JavaScript AST (as per the [Mozilla parser API][api], except
+// that:
+//
+// - Return outside functions is allowed
+//
+// - Label consistency (no conflicts, break only to existing labels)
+//   is not enforced.
+//
+// - Bogus Identifier nodes with a name of `"✖"` are inserted whenever
+//   the parser got too confused to return anything meaningful.
+//
+// [api]: https://developer.mozilla.org/en-US/docs/SpiderMonkey/Parser_API
+//
+// The expected use for this is to *first* try `acorn.parse`, and only
+// if that fails switch to `parse_dammit`. The loose parser might
+// parse badly indented code incorrectly, so **don't** use it as
+// your default parser.
+//
+// Quite a lot of acorn.js is duplicated here. The alternative was to
+// add a *lot* of extra cruft to that file, making it less readable
+// and slower. Copying and editing the code allowed me to make
+// invasive changes and simplifications without creating a complicated
+// tangle.
+
+(function(root, mod) {
+  if (typeof exports == "object" && typeof module == "object") return mod(exports, require("./acorn")); // CommonJS
+  if (typeof define == "function" && define.amd) return define(["exports", "./acorn"], mod); // AMD
+  mod(root.acorn || (root.acorn = {}), root.acorn); // Plain browser env
+})(this, function(exports, acorn) {
+  "use strict";
+
+  var tt = acorn.tokTypes;
+
+  var options, input, fetchToken, context;
+
+  acorn.defaultOptions.tabSize = 4;
+
+  exports.parse_dammit = function(inpt, opts) {
+    if (!opts) opts = {};
+    input = String(inpt);
+    fetchToken = acorn.tokenize(input, opts);
+    options = fetchToken.options;
+    sourceFile = options.sourceFile || null;
+    context = [];
+    nextLineStart = 0;
+    ahead.length = 0;
+    next();
+    return parseTopLevel();
+  };
+
+  var lastEnd, token = {start: 0, end: 0}, ahead = [];
+  var curLineStart, nextLineStart, curIndent, lastEndLoc, sourceFile;
+
+  function next(forceRegexp) {
+    lastEnd = token.end;
+    if (options.locations)
+      lastEndLoc = token.endLoc;
+    if (forceRegexp)
+      ahead.length = 0;
+
+    token = ahead.shift() || readToken(forceRegexp);
+
+    if (token.start >= nextLineStart) {
+      while (token.start >= nextLineStart) {
+        curLineStart = nextLineStart;
+        nextLineStart = lineEnd(curLineStart) + 1;
+      }
+      curIndent = indentationAfter(curLineStart);
+    }
+  }
+
+  function readToken(forceRegexp) {
+    for (;;) {
+      try {
+        var tok = fetchToken(forceRegexp);
+        if (tok.type === tt.dot && input.substr(tok.end, 1) === '.') {
+          tok = fetchToken();
+          tok.start--;
+          tok.type = tt.ellipsis;
+        }
+        return tok;
+      } catch(e) {
+        if (!(e instanceof SyntaxError)) throw e;
+
+        // Try to skip some text, based on the error message, and then continue
+        var msg = e.message, pos = e.raisedAt, replace = true;
+        if (/unterminated/i.test(msg)) {
+          pos = lineEnd(e.pos + 1);
+          if (/string/.test(msg)) {
+            replace = {start: e.pos, end: pos, type: tt.string, value: input.slice(e.pos + 1, pos)};
+          } else if (/regular expr/i.test(msg)) {
+            var re = input.slice(e.pos, pos);
+            try { re = new RegExp(re); } catch(e) {}
+            replace = {start: e.pos, end: pos, type: tt.regexp, value: re};
+          } else if (/template/.test(msg)) {
+            replace = {start: e.pos, end: pos,
+                       type: input.charAt(e.pos) == "`" ? tt.template : tt.templateContinued,
+                       value: input.slice(e.pos + 1, pos)};
+          } else {
+            replace = false;
+          }
+        } else if (/invalid (unicode|regexp|number)|expecting unicode|octal literal|is reserved|directly after number/i.test(msg)) {
+          while (pos < input.length && !isSpace(input.charCodeAt(pos))) ++pos;
+        } else if (/character escape|expected hexadecimal/i.test(msg)) {
+          while (pos < input.length) {
+            var ch = input.charCodeAt(pos++);
+            if (ch === 34 || ch === 39 || isNewline(ch)) break;
+          }
+        } else if (/unexpected character/i.test(msg)) {
+          pos++;
+          replace = false;
+        } else if (/regular expression/i.test(msg)) {
+          replace = true;
+        } else {
+          throw e;
+        }
+        resetTo(pos);
+        if (replace === true) replace = {start: pos, end: pos, type: tt.name, value: "✖"};
+        if (replace) {
+          if (options.locations) {
+            replace.startLoc = acorn.getLineInfo(input, replace.start);
+            replace.endLoc = acorn.getLineInfo(input, replace.end);
+          }
+          return replace;
+        }
+      }
+    }
+  }
+
+  function resetTo(pos) {
+    for (;;) {
+      try {
+        var ch = input.charAt(pos - 1);
+        var reAllowed = !ch || /[\[\{\(,;:?\/*=+\-~!|&%^<>]/.test(ch) ||
+          /[enwfd]/.test(ch) && /\b(keywords|case|else|return|throw|new|in|(instance|type)of|delete|void)$/.test(input.slice(pos - 10, pos));
+        return fetchToken.jumpTo(pos, reAllowed);
+      } catch(e) {
+        if (!(e instanceof SyntaxError && /unterminated comment/i.test(e.message))) throw e;
+        pos = lineEnd(e.pos + 1);
+        if (pos >= input.length) return;
+      }
+    }
+  }
+
+  function lookAhead(n) {
+    while (n > ahead.length)
+      ahead.push(readToken());
+    return ahead[n-1];
+  }
+
+  var newline = /[\n\r\u2028\u2029]/;
+
+  function isNewline(ch) {
+    return ch === 10 || ch === 13 || ch === 8232 || ch === 8329;
+  }
+  function isSpace(ch) {
+    return (ch < 14 && ch > 8) || ch === 32 || ch === 160 || isNewline(ch);
+  }
+
+  function pushCx() {
+    context.push(curIndent);
+  }
+  function popCx() {
+    curIndent = context.pop();
+  }
+
+  function lineEnd(pos) {
+    while (pos < input.length && !isNewline(input.charCodeAt(pos))) ++pos;
+    return pos;
+  }
+  function indentationAfter(pos) {
+    for (var count = 0;; ++pos) {
+      var ch = input.charCodeAt(pos);
+      if (ch === 32) ++count;
+      else if (ch === 9) count += options.tabSize;
+      else return count;
+    }
+  }
+
+  function closes(closeTok, indent, line, blockHeuristic) {
+    if (token.type === closeTok || token.type === tt.eof) return true;
+    if (line != curLineStart && curIndent < indent && tokenStartsLine() &&
+        (!blockHeuristic || nextLineStart >= input.length ||
+         indentationAfter(nextLineStart) < indent)) return true;
+    return false;
+  }
+
+  function tokenStartsLine() {
+    for (var p = token.start - 1; p >= curLineStart; --p) {
+      var ch = input.charCodeAt(p);
+      if (ch !== 9 && ch !== 32) return false;
+    }
+    return true;
+  }
+
+  function Node(start) {
+    this.type = null;
+    this.start = start;
+    this.end = null;
+  }
+  Node.prototype = acorn.Node.prototype;
+
+  function SourceLocation(start) {
+    this.start = start || token.startLoc || {line: 1, column: 0};
+    this.end = null;
+    if (sourceFile !== null) this.source = sourceFile;
+  }
+
+  function startNode() {
+    var node = new Node(token.start);
+    if (options.locations)
+      node.loc = new SourceLocation();
+    if (options.directSourceFile)
+      node.sourceFile = options.directSourceFile;
+    if (options.ranges)
+      node.range = [token.start, 0];
+    return node;
+  }
+
+  function storeCurrentPos() {
+    return options.locations ? [token.start, token.startLoc] : token.start;
+  }
+
+  function startNodeAt(pos) {
+    var node;
+    if (options.locations) {
+      node = new Node(pos[0]);
+      node.loc = new SourceLocation(pos[1]);
+    } else {
+      node = new Node(pos);
+    }
+    if (options.directSourceFile)
+      node.sourceFile = options.directSourceFile;
+    if (options.ranges)
+      node.range = [pos[0], 0];
+    return node;
+  }
+
+  function finishNode(node, type) {
+    node.type = type;
+    node.end = lastEnd;
+    if (options.locations)
+      node.loc.end = lastEndLoc;
+    if (options.ranges)
+      node.range[1] = lastEnd;
+    return node;
+  }
+
+  function finishNodeAt(node, type, pos) {
+    if (options.locations) { node.loc.end = pos[1]; pos = pos[0]; }
+    node.type = type;
+    node.end = pos;
+    if (options.ranges) node.range[1] = pos;
+    return node;
+  }
+
+  function dummyIdent() {
+    var dummy = startNode();
+    dummy.name = "✖";
+    return finishNode(dummy, "Identifier");
+  }
+  function isDummy(node) { return node.name == "✖"; }
+
+  function eat(type) {
+    if (token.type === type) {
+      next();
+      return true;
+    } else {
+      return false;
+    }
+  }
+
+  function canInsertSemicolon() {
+    return (token.type === tt.eof || token.type === tt.braceR || newline.test(input.slice(lastEnd, token.start)));
+  }
+  function semicolon() {
+    return eat(tt.semi);
+  }
+
+  function expect(type) {
+    if (eat(type)) return true;
+    if (lookAhead(1).type == type) {
+      next(); next();
+      return true;
+    }
+    if (lookAhead(2).type == type) {
+      next(); next(); next();
+      return true;
+    }
+  }
+
+  function checkLVal(expr) {
+    if (!expr) return expr;
+    switch (expr.type) {
+      case "Identifier":
+      case "MemberExpression":
+      case "ObjectPattern":
+      case "ArrayPattern":
+      case "SpreadElement":
+        return expr;
+
+      default:
+        return dummyIdent();
+    }
+  }
+
+  function parseTopLevel() {
+    var node = startNodeAt(options.locations ? [0, acorn.getLineInfo(input, 0)] : 0);
+    node.body = [];
+    while (token.type !== tt.eof) node.body.push(parseStatement());
+    lastEnd = token.end;
+    lastEndLoc = token.endLoc;
+    return finishNode(node, "Program");
+  }
+
+  function parseStatement() {
+    if (token.type === tt.slash || token.type === tt.assign && token.value === "/=")
+      next(true);
+
+    var starttype = token.type, node = startNode();
+
+    switch (starttype) {
+    case tt._break: case tt._continue:
+      next();
+      var isBreak = starttype === tt._break;
+      if (semicolon() || canInsertSemicolon()) {
+        node.label = null;
+      } else {
+        node.label = token.type === tt.name ? parseIdent() : null;
+        semicolon();
+      }
+      return finishNode(node, isBreak ? "BreakStatement" : "ContinueStatement");
+
+    case tt._debugger:
+      next();
+      semicolon();
+      return finishNode(node, "DebuggerStatement");
+
+    case tt._do:
+      next();
+      node.body = parseStatement();
+      node.test = eat(tt._while) ? parseParenExpression() : dummyIdent();
+      semicolon();
+      return finishNode(node, "DoWhileStatement");
+
+    case tt._for:
+      next();
+      pushCx();
+      expect(tt.parenL);
+      if (token.type === tt.semi) return parseFor(node, null);
+      if (token.type === tt._var || token.type === tt._let) {
+        var init = parseVar(true);
+        if (init.declarations.length === 1 && (token.type === tt._in || token.type === tt.name && token.value === "of")) {
+          return parseForIn(node, init);
+        }
+        return parseFor(node, init);
+      }
+      var init = parseExpression(false, true);
+      if (token.type === tt._in || token.type === tt.name && token.value === "of") {
+        return parseForIn(node, checkLVal(init));
+      }
+      return parseFor(node, init);
+
+    case tt._function:
+      next();
+      return parseFunction(node, true);
+
+    case tt._if:
+      next();
+      node.test = parseParenExpression();
+      node.consequent = parseStatement();
+      node.alternate = eat(tt._else) ? parseStatement() : null;
+      return finishNode(node, "IfStatement");
+
+    case tt._return:
+      next();
+      if (eat(tt.semi) || canInsertSemicolon()) node.argument = null;
+      else { node.argument = parseExpression(); semicolon(); }
+      return finishNode(node, "ReturnStatement");
+
+    case tt._switch:
+      var blockIndent = curIndent, line = curLineStart;
+      next();
+      node.discriminant = parseParenExpression();
+      node.cases = [];
+      pushCx();
+      expect(tt.braceL);
+
+      for (var cur; !closes(tt.braceR, blockIndent, line, true);) {
+        if (token.type === tt._case || token.type === tt._default) {
+          var isCase = token.type === tt._case;
+          if (cur) finishNode(cur, "SwitchCase");
+          node.cases.push(cur = startNode());
+          cur.consequent = [];
+          next();
+          if (isCase) cur.test = parseExpression();
+          else cur.test = null;
+          expect(tt.colon);
+        } else {
+          if (!cur) {
+            node.cases.push(cur = startNode());
+            cur.consequent = [];
+            cur.test = null;
+          }
+          cur.consequent.push(parseStatement());
+        }
+      }
+      if (cur) finishNode(cur, "SwitchCase");
+      popCx();
+      eat(tt.braceR);
+      return finishNode(node, "SwitchStatement");
+
+    case tt._throw:
+      next();
+      node.argument = parseExpression();
+      semicolon();
+      return finishNode(node, "ThrowStatement");
+
+    case tt._try:
+      next();
+      node.block = parseBlock();
+      node.handler = null;
+      if (token.type === tt._catch) {
+        var clause = startNode();
+        next();
+        expect(tt.parenL);
+        clause.param = parseIdent();
+        expect(tt.parenR);
+        clause.guard = null;
+        clause.body = parseBlock();
+        node.handler = finishNode(clause, "CatchClause");
+      }
+      node.finalizer = eat(tt._finally) ? parseBlock() : null;
+      if (!node.handler && !node.finalizer) return node.block;
+      return finishNode(node, "TryStatement");
+
+    case tt._var:
+    case tt._let:
+    case tt._const:
+      return parseVar();
+
+    case tt._while:
+      next();
+      node.test = parseParenExpression();
+      node.body = parseStatement();
+      return finishNode(node, "WhileStatement");
+
+    case tt._with:
+      next();
+      node.object = parseParenExpression();
+      node.body = parseStatement();
+      return finishNode(node, "WithStatement");
+
+    case tt.braceL:
+      return parseBlock();
+
+    case tt.semi:
+      next();
+      return finishNode(node, "EmptyStatement");
+
+    case tt._class:
+      return parseObj(true, true);
+
+    case tt._import:
+      return parseImport();
+
+    case tt._export:
+      return parseExport();
+
+    default:
+      var expr = parseExpression();
+      if (isDummy(expr)) {
+        next();
+        if (token.type === tt.eof) return finishNode(node, "EmptyStatement");
+        return parseStatement();
+      } else if (starttype === tt.name && expr.type === "Identifier" && eat(tt.colon)) {
+        node.body = parseStatement();
+        node.label = expr;
+        return finishNode(node, "LabeledStatement");
+      } else {
+        node.expression = expr;
+        semicolon();
+        return finishNode(node, "ExpressionStatement");
+      }
+    }
+  }
+
+  function parseBlock() {
+    var node = startNode();
+    pushCx();
+    expect(tt.braceL);
+    var blockIndent = curIndent, line = curLineStart;
+    node.body = [];
+    while (!closes(tt.braceR, blockIndent, line, true))
+      node.body.push(parseStatement());
+    popCx();
+    eat(tt.braceR);
+    return finishNode(node, "BlockStatement");
+  }
+
+  function parseFor(node, init) {
+    node.init = init;
+    node.test = node.update = null;
+    if (eat(tt.semi) && token.type !== tt.semi) node.test = parseExpression();
+    if (eat(tt.semi) && token.type !== tt.parenR) node.update = parseExpression();
+    popCx();
+    expect(tt.parenR);
+    node.body = parseStatement();
+    return finishNode(node, "ForStatement");
+  }
+
+  function parseForIn(node, init) {
+    var type = token.type === tt._in ? "ForInStatement" : "ForOfStatement";
+    next();
+    node.left = init;
+    node.right = parseExpression();
+    popCx();
+    expect(tt.parenR);
+    node.body = parseStatement();
+    return finishNode(node, type);
+  }
+
+  function parseVar(noIn) {
+    var node = startNode();
+    node.kind = token.type.keyword;
+    next();
+    node.declarations = [];
+    do {
+      var decl = startNode();
+      decl.id = options.ecmaVersion >= 6 ? toAssignable(parseExprAtom()) : parseIdent();
+      decl.init = eat(tt.eq) ? parseExpression(true, noIn) : null;
+      node.declarations.push(finishNode(decl, "VariableDeclarator"));
+    } while (eat(tt.comma));
+    if (!node.declarations.length) {
+      var decl = startNode();
+      decl.id = dummyIdent();
+      node.declarations.push(finishNode(decl, "VariableDeclarator"));
+    }
+    if (!noIn) semicolon();
+    return finishNode(node, "VariableDeclaration");
+  }
+
+  function parseExpression(noComma, noIn) {
+    var start = storeCurrentPos();
+    var expr = parseMaybeAssign(noIn);
+    if (!noComma && token.type === tt.comma) {
+      var node = startNodeAt(start);
+      node.expressions = [expr];
+      while (eat(tt.comma)) node.expressions.push(parseMaybeAssign(noIn));
+      return finishNode(node, "SequenceExpression");
+    }
+    return expr;
+  }
+
+  function parseParenExpression() {
+    pushCx();
+    expect(tt.parenL);
+    var val = parseExpression();
+    popCx();
+    expect(tt.parenR);
+    return val;
+  }
+
+  function parseMaybeAssign(noIn) {
+    var start = storeCurrentPos();
+    var left = parseMaybeConditional(noIn);
+    if (token.type.isAssign) {
+      var node = startNodeAt(start);
+      node.operator = token.value;
+      node.left = token.type === tt.eq ? toAssignable(left) : checkLVal(left);
+      next();
+      node.right = parseMaybeAssign(noIn);
+      return finishNode(node, "AssignmentExpression");
+    }
+    return left;
+  }
+
+  function parseMaybeConditional(noIn) {
+    var start = storeCurrentPos();
+    var expr = parseExprOps(noIn);
+    if (eat(tt.question)) {
+      var node = startNodeAt(start);
+      node.test = expr;
+      node.consequent = parseExpression(true);
+      node.alternate = expect(tt.colon) ? parseExpression(true, noIn) : dummyIdent();
+      return finishNode(node, "ConditionalExpression");
+    }
+    return expr;
+  }
+
+  function parseExprOps(noIn) {
+    var start = storeCurrentPos();
+    var indent = curIndent, line = curLineStart;
+    return parseExprOp(parseMaybeUnary(noIn), start, -1, noIn, indent, line);
+  }
+
+  function parseExprOp(left, start, minPrec, noIn, indent, line) {
+    if (curLineStart != line && curIndent < indent && tokenStartsLine()) return left;
+    var prec = token.type.binop;
+    if (prec != null && (!noIn || token.type !== tt._in)) {
+      if (prec > minPrec) {
+        var node = startNodeAt(start);
+        node.left = left;
+        node.operator = token.value;
+        next();
+        if (curLineStart != line && curIndent < indent && tokenStartsLine()) {
+          node.right = dummyIdent();
+        } else {
+          var rightStart = storeCurrentPos();
+          node.right = parseExprOp(parseMaybeUnary(noIn), rightStart, prec, noIn, indent, line);
+        }
+        finishNode(node, /&&|\|\|/.test(node.operator) ? "LogicalExpression" : "BinaryExpression");
+        return parseExprOp(node, start, minPrec, noIn, indent, line);
+      }
+    }
+    return left;
+  }
+
+  function parseMaybeUnary(noIn) {
+    if (token.type.prefix) {
+      var node = startNode(), update = token.type.isUpdate, nodeType;
+      if (token.type === tt.ellipsis) {
+        nodeType = "SpreadElement";
+      } else {
+        nodeType = update ? "UpdateExpression" : "UnaryExpression";
+        node.operator = token.value;
+        node.prefix = true;
+      }
+      node.operator = token.value;
+      node.prefix = true;
+      next();
+      node.argument = parseMaybeUnary(noIn);
+      if (update) node.argument = checkLVal(node.argument);
+      return finishNode(node, nodeType);
+    }
+    var start = storeCurrentPos();
+    var expr = parseExprSubscripts();
+    while (token.type.postfix && !canInsertSemicolon()) {
+      var node = startNodeAt(start);
+      node.operator = token.value;
+      node.prefix = false;
+      node.argument = checkLVal(expr);
+      next();
+      expr = finishNode(node, "UpdateExpression");
+    }
+    return expr;
+  }
+
+  function parseExprSubscripts() {
+    var start = storeCurrentPos();
+    return parseSubscripts(parseExprAtom(), start, false, curIndent, curLineStart);
+  }
+
+  function parseSubscripts(base, start, noCalls, startIndent, line) {
+    for (;;) {
+      if (curLineStart != line && curIndent <= startIndent && tokenStartsLine()) {
+        if (token.type == tt.dot && curIndent == startIndent)
+          --startIndent;
+        else
+          return base;
+      }
+
+      if (eat(tt.dot)) {
+        var node = startNodeAt(start);
+        node.object = base;
+        if (curLineStart != line && curIndent <= startIndent && tokenStartsLine())
+          node.property = dummyIdent();
+        else
+          node.property = parsePropertyAccessor() || dummyIdent();
+        node.computed = false;
+        base = finishNode(node, "MemberExpression");
+      } else if (token.type == tt.bracketL) {
+        pushCx();
+        next();
+        var node = startNodeAt(start);
+        node.object = base;
+        node.property = parseExpression();
+        node.computed = true;
+        popCx();
+        expect(tt.bracketR);
+        base = finishNode(node, "MemberExpression");
+      } else if (!noCalls && token.type == tt.parenL) {
+        pushCx();
+        var node = startNodeAt(start);
+        node.callee = base;
+        node.arguments = parseExprList(tt.parenR);
+        base = finishNode(node, "CallExpression");
+      } else if (token.type == tt.template) {
+        var node = startNodeAt(start);
+        node.tag = base;
+        node.quasi = parseTemplate();
+        base = finishNode(node, "TaggedTemplateExpression");
+      } else {
+        return base;
+      }
+    }
+  }
+
+  function parseExprAtom() {
+    switch (token.type) {
+    case tt._this:
+      var node = startNode();
+      next();
+      return finishNode(node, "ThisExpression");
+
+    case tt.name:
+      var start = storeCurrentPos();
+      var id = parseIdent();
+      return eat(tt.arrow) ? parseArrowExpression(startNodeAt(start), [id]) : id;
+
+    case tt.regexp:
+      var node = startNode();
+      var val = token.value;
+      node.regex = {pattern: val.pattern, flags: val.flags};
+      node.value = val.value;
+      node.raw = input.slice(token.start, token.end);
+      next();
+      return finishNode(node, "Literal");
+
+    case tt.num: case tt.string:
+      var node = startNode();
+      node.value = token.value;
+      node.raw = input.slice(token.start, token.end);
+      next();
+      return finishNode(node, "Literal");
+
+    case tt._null: case tt._true: case tt._false:
+      var node = startNode();
+      node.value = token.type.atomValue;
+      node.raw = token.type.keyword;
+      next();
+      return finishNode(node, "Literal");
+
+    case tt.parenL:
+      var start = storeCurrentPos();
+      next();
+      var val = parseExpression();
+      expect(tt.parenR);
+      if (eat(tt.arrow)) {
+        return parseArrowExpression(startNodeAt(start), val.expressions || (isDummy(val) ? [] : [val]));
+      }
+      if (options.preserveParens) {
+        var par = startNodeAt(start);
+        par.expression = val;
+        val = finishNode(par, "ParenthesizedExpression");
+      }
+      return val;
+
+    case tt.bracketL:
+      var node = startNode();
+      pushCx();
+      node.elements = parseExprList(tt.bracketR, true);
+      return finishNode(node, "ArrayExpression");
+
+    case tt.braceL:
+      return parseObj();
+
+    case tt._class:
+      return parseObj(true);
+
+    case tt._function:
+      var node = startNode();
+      next();
+      return parseFunction(node, false);
+
+    case tt._new:
+      return parseNew();
+
+    case tt._yield:
+      var node = startNode();
+      next();
+      if (semicolon() || canInsertSemicolon()) {
+        node.delegate = false;
+        node.argument = null;
+      } else {
+        node.delegate = eat(tt.star);
+        node.argument = parseExpression(true);
+      }
+      return finishNode(node, "YieldExpression");
+
+    case tt.template:
+      return parseTemplate();
+
+    default:
+      return dummyIdent();
+    }
+  }
+
+  function parseNew() {
+    var node = startNode(), startIndent = curIndent, line = curLineStart;
+    next();
+    var start = storeCurrentPos();
+    node.callee = parseSubscripts(parseExprAtom(), start, true, startIndent, line);
+    if (token.type == tt.parenL) {
+      pushCx();
+      node.arguments = parseExprList(tt.parenR);
+    } else {
+      node.arguments = [];
+    }
+    return finishNode(node, "NewExpression");
+  }
+
+  function parseTemplateElement() {
+    var elem = startNodeAt(options.locations ? [token.start + 1, token.startLoc.offset(1)] : token.start + 1);
+    elem.value = token.value;
+    elem.tail = input.charCodeAt(token.end - 1) !== 123; // '{'
+    var endOff = elem.tail ? 1 : 2;
+    var endPos = options.locations ? [token.end - endOff, token.endLoc.offset(-endOff)] : token.end - endOff;
+    next();
+    return finishNodeAt(elem, "TemplateElement", endPos);
+  }
+
+  function parseTemplate() {
+    var node = startNode();
+    node.expressions = [];
+    var curElt = parseTemplateElement();
+    node.quasis = [curElt];
+    while (!curElt.tail) {
+      var next = parseExpression();
+      if (isDummy(next)) {
+        node.quasis[node.quasis.length - 1].tail = true;
+        break;
+      }
+      node.expressions.push(next);
+      if (token.type === tt.templateContinued) {
+        node.quasis.push(curElt = parseTemplateElement());
+      } else {
+        curElt = startNode();
+        curElt.value = {cooked: "", raw: ""};
+        curElt.tail = true;
+        node.quasis.push(curElt);
+      }
+    }
+    return finishNode(node, "TemplateLiteral");
+  }
+
+  function parseObj(isClass, isStatement) {
+    var node = startNode();
+    if (isClass) {
+      next();
+      if (token.type === tt.name) node.id = parseIdent();
+      else if (isStatement) node.id = dummyIdent();
+      node.superClass = eat(tt._extends) ? parseExpression() : null;
+      node.body = startNode();
+      node.body.body = [];
+    } else {
+      node.properties = [];
+    }
+    pushCx();
+    var indent = curIndent + 1, line = curLineStart;
+    eat(tt.braceL);
+    if (curIndent + 1 < indent) { indent = curIndent; line = curLineStart; }
+    while (!closes(tt.braceR, indent, line)) {
+      var prop = startNode(), isGenerator;
+      if (options.ecmaVersion >= 6) {
+        if (isClass) {
+          if (prop['static'] = (token.type === tt.name && token.value === "static")) next();
+        } else {
+          prop.method = false;
+          prop.shorthand = false;
+        }
+        isGenerator = eat(tt.star);
+      }
+      parsePropertyName(prop);
+      if (isDummy(prop.key)) { if (isDummy(parseExpression(true))) next(); eat(tt.comma); continue; }
+      if (!isClass && eat(tt.colon)) {
+        prop.kind = "init";
+        prop.value = parseExpression(true);
+      } else if (options.ecmaVersion >= 6 && (token.type === tt.parenL || token.type === tt.braceL)) {
+        if (isClass) {
+          prop.kind = "";
+        } else {
+          prop.kind = "init";
+          prop.method = true;
+        }
+        prop.value = parseMethod(isGenerator);
+      } else if (options.ecmaVersion >= 5 && prop.key.type === "Identifier" &&
+                 (prop.key.name === "get" || prop.key.name === "set")) {
+        prop.kind = prop.key.name;
+        parsePropertyName(prop);
+        prop.value = parseMethod(false);
+      } else if (isClass) {
+        prop.kind = "";
+        prop.value = parseMethod(isGenerator);
+      } else {
+        prop.kind = "init";
+        prop.value = options.ecmaVersion >= 6 ? prop.key : dummyIdent();
+        prop.shorthand = true;
+      }
+
+      if (isClass) {
+        node.body.body.push(finishNode(prop, "MethodDefinition"));
+        semicolon();
+      } else {
+        node.properties.push(finishNode(prop, "Property"));
+        eat(tt.comma);
+      }
+    }
+    popCx();
+    if (!eat(tt.braceR)) {
+      // If there is no closing brace, make the node span to the start
+      // of the next token (this is useful for Tern)
+      lastEnd = token.start;
+      if (options.locations) lastEndLoc = token.startLoc;
+    }
+    if (isClass) {
+      semicolon();
+      finishNode(node.body, "ClassBody");
+      return finishNode(node, isStatement ? "ClassDeclaration" : "ClassExpression");
+    } else {
+      return finishNode(node, "ObjectExpression");
+    }
+  }
+
+  function parsePropertyName(prop) {
+    if (options.ecmaVersion >= 6) {
+      if (eat(tt.bracketL)) {
+        prop.computed = true;
+        prop.key = parseExpression();
+        expect(tt.bracketR);
+        return;
+      } else {
+        prop.computed = false;
+      }
+    }
+    var key = (token.type === tt.num || token.type === tt.string) ? parseExprAtom() : parseIdent();
+    prop.key = key || dummyIdent();
+  }
+
+  function parsePropertyAccessor() {
+    if (token.type === tt.name || token.type.keyword) return parseIdent();
+  }
+
+  function parseIdent() {
+    var node = startNode();
+    node.name = token.type === tt.name ? token.value : token.type.keyword;
+    fetchToken.noRegexp();
+    next();
+    return finishNode(node, "Identifier");
+  }
+
+  function initFunction(node) {
+    node.id = null;
+    node.params = [];
+    if (options.ecmaVersion >= 6) {
+      node.defaults = [];
+      node.rest = null;
+      node.generator = false;
+      node.expression = false;
+    }
+  }
+
+  // Convert existing expression atom to assignable pattern
+  // if possible.
+
+  function toAssignable(node) {
+    if (options.ecmaVersion >= 6 && node) {
+      switch (node.type) {
+        case "ObjectExpression":
+          node.type = "ObjectPattern";
+          var props = node.properties;
+          for (var i = 0; i < props.length; i++) {
+            props[i].value = toAssignable(props[i].value);
+          }
+          break;
+
+        case "ArrayExpression":
+          node.type = "ArrayPattern";
+          var elms = node.elements;
+          for (var i = 0; i < elms.length; i++) {
+            elms[i] = toAssignable(elms[i]);
+          }
+          break;
+
+        case "SpreadElement":
+          node.argument = toAssignable(node.argument);
+          break;
+      }
+    }
+    return checkLVal(node);
+  }
+
+  function parseFunctionParams(node, params) {
+    var defaults = [], hasDefaults = false;
+
+    if (!params) {
+      pushCx();
+      params = parseExprList(tt.parenR);
+    }
+    for (var i = 0; i < params.length; i++) {
+      var param = params[i], defValue = null;
+      if (param.type === "AssignmentExpression") {
+        defValue = param.right;
+        param = param.left;
+      }
+      param = toAssignable(param);
+      if (param.type === "SpreadElement") {
+        param = param.argument;
+        if (i === params.length - 1) {
+          node.rest = param;
+          continue;
+        }
+      }
+      node.params.push(param);
+      defaults.push(defValue);
+      if (defValue) hasDefaults = true;
+    }
+
+    if (hasDefaults) node.defaults = defaults;
+  }
+
+  function parseFunction(node, isStatement) {
+    initFunction(node);
+    if (options.ecmaVersion >= 6) {
+      node.generator = eat(tt.star);
+    }
+    if (token.type === tt.name) node.id = parseIdent();
+    else if (isStatement) node.id = dummyIdent();
+    parseFunctionParams(node);
+    node.body = parseBlock();
+    return finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
+  }
+
+  function parseMethod(isGenerator) {
+    var node = startNode();
+    initFunction(node);
+    parseFunctionParams(node);
+    node.generator = isGenerator || false;
+    node.expression = options.ecmaVersion >= 6 && token.type !== tt.braceL;
+    node.body = node.expression ? parseExpression(true) : parseBlock();
+    return finishNode(node, "FunctionExpression");
+  }
+
+  function parseArrowExpression(node, params) {
+    initFunction(node);
+    parseFunctionParams(node, params);
+    node.expression = token.type !== tt.braceL;
+    node.body = node.expression ? parseExpression(true) : parseBlock();
+    return finishNode(node, "ArrowFunctionExpression");
+  }
+
+  function parseExport() {
+    var node = startNode();
+    next();
+    node['default'] = eat(tt._default);
+    node.specifiers = node.source = null;
+    if (node['default']) {
+      node.declaration = parseExpression();
+      semicolon();
+    } else if (token.type.keyword) {
+      node.declaration = parseStatement();
+    } else {
+      node.declaration = null;
+      parseSpecifierList(node, "Export");
+    }
+    semicolon();
+    return finishNode(node, "ExportDeclaration");
+  }
+
+  function parseImport() {
+    var node = startNode();
+    next();
+    if (token.type === tt.string) {
+      node.specifiers = [];
+      node.source = parseExprAtom();
+      node.kind = '';
+    } else {
+      if (token.type === tt.name && token.value !== "from") {
+        var elt = startNode();
+        elt.id = parseIdent();
+        elt.name = null;
+        elt['default'] = true;
+        finishNode(elt, "ImportSpecifier");
+        eat(tt.comma);
+      }
+      parseSpecifierList(node, "Import");
+      var specs = node.specifiers;
+      for (var i = 0; i < specs.length; i++) specs[i]['default'] = false;
+      if (elt) node.specifiers.unshift(elt);
+    }
+    semicolon();
+    return finishNode(node, "ImportDeclaration");
+  }
+
+  function parseSpecifierList(node, prefix) {
+    var elts = node.specifiers = [];
+    if (token.type === tt.star) {
+      var elt = startNode();
+      next();
+      if (token.type === tt.name && token.value === "as") {
+        next();
+        elt.name = parseIdent();
+      }
+      elts.push(finishNode(elt, prefix + "BatchSpecifier"));
+    } else {
+      var indent = curIndent, line = curLineStart, continuedLine = nextLineStart;
+      pushCx();
+      eat(tt.braceL);
+      if (curLineStart > continuedLine) continuedLine = curLineStart;
+      while (!closes(tt.braceR, indent + (curLineStart <= continuedLine ? 1 : 0), line)) {
+        var elt = startNode();
+        if (token.type === tt.star) {
+          next();
+          if (token.type === tt.name && token.value === "as") {
+            next();
+            elt.name = parseIdent();
+          }
+          finishNode(elt, prefix + "BatchSpecifier");
+        } else {
+          if (token.type === tt.name && token.value === "from") break;
+          elt.id = parseIdent();
+          if (token.type === tt.name && token.value === "as") {
+            next();
+            elt.name = parseIdent();
+          } else {
+            elt.name = null;
+          }
+          finishNode(elt, prefix + "Specifier");
+        }
+        elts.push(elt);
+        eat(tt.comma);
+      }
+      eat(tt.braceR);
+      popCx();
+    }
+    if (token.type === tt.name && token.value === "from") {
+      next();
+      node.source = parseExprAtom();
+    } else {
+      node.source = null;
+    }
+  }
+
+  function parseExprList(close, allowEmpty) {
+    var indent = curIndent, line = curLineStart, elts = [];
+    next(); // Opening bracket
+    while (!closes(close, indent + 1, line)) {
+      if (eat(tt.comma)) {
+        elts.push(allowEmpty ? null : dummyIdent());
+        continue;
+      }
+      var elt = parseExpression(true);
+      if (isDummy(elt)) {
+        if (closes(close, indent, line)) break;
+        next();
+      } else {
+        elts.push(elt);
+      }
+      eat(tt.comma);
+    }
+    popCx();
+    if (!eat(close)) {
+      // If there is no closing brace, make the node span to the start
+      // of the next token (this is useful for Tern)
+      lastEnd = token.start;
+      if (options.locations) lastEndLoc = token.startLoc;
+    }
+    return elts;
+  }
+});

File diff suppressed because it is too large
+ 109 - 0
AtomicEditor/EditorResources/AtomicEditor/javascript/modules/beautify.js


BIN
AtomicEditor/EditorResources/AtomicEditor/resources/MesloLGL-Bold.ttf


BIN
AtomicEditor/EditorResources/AtomicEditor/resources/MesloLGL-BoldItalic.ttf


BIN
AtomicEditor/EditorResources/AtomicEditor/resources/MesloLGL-Italic.ttf


Some files were not shown because too many files changed in this diff