diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml
index 8c14141445..7ff5d633b3 100644
--- a/android/AndroidManifest.xml
+++ b/android/AndroidManifest.xml
@@ -6,6 +6,8 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/res/layout/gdxdialogs_inputtext.xml b/android/res/layout/gdxdialogs_inputtext.xml
new file mode 100755
index 0000000000..656600a753
--- /dev/null
+++ b/android/res/layout/gdxdialogs_inputtext.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java
index 698b5697f9..18b98c3c97 100644
--- a/android/src/io/anuke/mindustry/AndroidLauncher.java
+++ b/android/src/io/anuke/mindustry/AndroidLauncher.java
@@ -15,6 +15,7 @@ import android.os.Bundle;
import android.telephony.TelephonyManager;
import io.anuke.mindustry.io.PlatformFunction;
import io.anuke.ucore.function.Callable;
+import io.anuke.ucore.scene.ui.TextField;
import io.anuke.ucore.scene.ui.layout.Unit;
public class AndroidLauncher extends AndroidApplication{
@@ -47,6 +48,11 @@ public class AndroidLauncher extends AndroidApplication{
Intent intent = new Intent( Intent.ACTION_VIEW, marketUri );
startActivity(intent);
}
+
+ @Override
+ public void addDialog(TextField field){
+ TextFieldDialogListener.add(field);
+ }
};
Mindustry.donationsCallable = new Callable(){ @Override public void run(){ showDonations(); } };
diff --git a/android/src/io/anuke/mindustry/AndroidTextFieldDialog.java b/android/src/io/anuke/mindustry/AndroidTextFieldDialog.java
new file mode 100644
index 0000000000..6d1a2a83a4
--- /dev/null
+++ b/android/src/io/anuke/mindustry/AndroidTextFieldDialog.java
@@ -0,0 +1,135 @@
+package io.anuke.mindustry;
+
+
+import com.badlogic.gdx.Gdx;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.text.InputFilter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager.LayoutParams;
+import android.widget.EditText;
+
+public class AndroidTextFieldDialog{
+ private Activity activity;
+ private EditText userInput;
+ private AlertDialog.Builder builder;
+ private TextPromptListener listener;
+ private boolean isBuild;
+
+ public AndroidTextFieldDialog() {
+ this.activity = (Activity)Gdx.app;
+ load();
+ }
+
+ public AndroidTextFieldDialog show() {
+
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Gdx.app.error("Android Dialogs", AndroidTextFieldDialog.class.getSimpleName() + " now shown.");
+ AlertDialog dialog = builder.create();
+
+ dialog.getWindow().setSoftInputMode(LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+
+ dialog.show();
+
+ }
+ });
+
+ return this;
+ }
+
+ private AndroidTextFieldDialog load() {
+
+ activity.runOnUiThread(new Runnable() {
+
+ @Override
+ public void run() {
+
+ AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(activity);
+ LayoutInflater li = LayoutInflater.from(activity);
+
+ View promptsView = li.inflate(getResourceId("gdxdialogs_inputtext", "layout"), null);
+
+ alertDialogBuilder.setView(promptsView);
+
+ userInput = (EditText) promptsView.findViewById(getResourceId("gdxDialogsEditTextInput", "id"));
+
+ alertDialogBuilder.setCancelable(false);
+ builder = alertDialogBuilder;
+
+ isBuild = true;
+ }
+ });
+
+ // Wait till TextPrompt is built.
+ while (!isBuild) {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ }
+ }
+
+ return this;
+ }
+
+ public int getResourceId(String pVariableName, String pVariableType) {
+ try {
+ return activity.getResources().getIdentifier(pVariableName, pVariableType, activity.getPackageName());
+ } catch (Exception e) {
+ Gdx.app.error("Android Dialogs", "Cannot find resouce with name: " + pVariableName
+ + " Did you copy the layouts to /res/layouts and /res/layouts_v14 ?");
+ e.printStackTrace();
+ return -1;
+ }
+ }
+
+ public AndroidTextFieldDialog setText(CharSequence value) {
+ userInput.append(value);
+ return this;
+ }
+
+ public AndroidTextFieldDialog setCancelButtonLabel(CharSequence label) {
+ builder.setNegativeButton(label, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.cancel();
+ }
+ });
+ return this;
+ }
+
+ public AndroidTextFieldDialog setConfirmButtonLabel(CharSequence label) {
+ builder.setPositiveButton(label, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ if (listener != null && !userInput.getText().toString().isEmpty()) {
+ listener.confirm(userInput.getText().toString());
+ }
+
+ }
+ });
+ return this;
+ }
+
+ public AndroidTextFieldDialog setTextPromptListener(TextPromptListener listener) {
+ this.listener = listener;
+ return this;
+ }
+
+ public AndroidTextFieldDialog setInputType(int type) {
+ userInput.setInputType(type);
+ return this;
+ }
+
+ public AndroidTextFieldDialog setMaxLength(int length) {
+ userInput.setFilters(new InputFilter[] { new InputFilter.LengthFilter(length) });
+ return this;
+ }
+
+ public static interface TextPromptListener{
+ public void confirm(String text);
+ }
+
+}
diff --git a/android/src/io/anuke/mindustry/TextFieldDialogListener.java b/android/src/io/anuke/mindustry/TextFieldDialogListener.java
new file mode 100644
index 0000000000..bb2e935d59
--- /dev/null
+++ b/android/src/io/anuke/mindustry/TextFieldDialogListener.java
@@ -0,0 +1,71 @@
+package io.anuke.mindustry;
+
+
+import com.badlogic.gdx.Application.ApplicationType;
+import com.badlogic.gdx.Gdx;
+
+import android.text.InputType;
+import io.anuke.mindustry.AndroidTextFieldDialog.TextPromptListener;
+import io.anuke.ucore.scene.event.InputEvent;
+import io.anuke.ucore.scene.event.InputListener;
+import io.anuke.ucore.scene.ui.TextField;
+import io.anuke.ucore.scene.utils.ChangeListener;
+import io.anuke.ucore.scene.utils.ClickListener;
+
+public class TextFieldDialogListener extends ClickListener{
+ private TextField field;
+ private int type;
+ private int max;
+
+ public static void add(TextField field, int type, int max){
+ field.addListener(new TextFieldDialogListener(field, type, max));
+ field.addListener(new InputListener(){
+ public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
+ Gdx.input.setOnscreenKeyboardVisible(false);
+ return false;
+ }
+ });
+ }
+
+ public static void add(TextField field){
+ add(field, 0, 15);
+ }
+
+ //type - 0 is text, 1 is numbers, 2 is decimals
+ public TextFieldDialogListener(TextField field, int type, int max){
+ this.field = field;
+ this.type = type;
+ this.max = max;
+ }
+
+ public void clicked(final InputEvent event, float x, float y){
+
+ if(Gdx.app.getType() == ApplicationType.Desktop) return;
+
+ AndroidTextFieldDialog dialog = new AndroidTextFieldDialog();
+
+ dialog.setTextPromptListener(new TextPromptListener(){
+ public void confirm(String text){
+ field.clearText();
+ field.appendText(text);
+ field.fire(new ChangeListener.ChangeEvent());
+ Gdx.graphics.requestRendering();
+ }
+ });
+
+ if(type == 0){
+ dialog.setInputType(InputType.TYPE_CLASS_TEXT);
+ }else if(type == 1){
+ dialog.setInputType(InputType.TYPE_CLASS_NUMBER);
+ }else if(type == 2){
+ dialog.setInputType(InputType.TYPE_NUMBER_FLAG_DECIMAL);
+ }
+
+ dialog.setConfirmButtonLabel("OK").setText(field.getText());
+ dialog.setCancelButtonLabel("Cancel");
+ dialog.setMaxLength(max);
+ dialog.show();
+ event.cancel();
+
+ }
+}
diff --git a/build.gradle b/build.gradle
index 41c2c5e07b..b9a26c5ee0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -79,7 +79,7 @@ project(":core") {
apply plugin: "java"
dependencies {
- compile 'com.github.anuken:ucore:9c523c4'
+ compile 'com.github.anuken:ucore:a525ad2043'
compile "com.badlogicgames.gdx:gdx:$gdxVersion"
compile "com.badlogicgames.gdx:gdx-ai:1.8.1"
}
diff --git a/core/assets-raw/sprites/ui/icon-file-text.png b/core/assets-raw/sprites/ui/icon-file-text.png
new file mode 100755
index 0000000000..3aea932bbb
Binary files /dev/null and b/core/assets-raw/sprites/ui/icon-file-text.png differ
diff --git a/core/assets-raw/sprites/ui/icon-file.png b/core/assets-raw/sprites/ui/icon-file.png
new file mode 100644
index 0000000000..8ebd7eba64
Binary files /dev/null and b/core/assets-raw/sprites/ui/icon-file.png differ
diff --git a/core/assets-raw/sprites/ui/icon-folder-parent.png b/core/assets-raw/sprites/ui/icon-folder-parent.png
new file mode 100755
index 0000000000..82b70ca831
Binary files /dev/null and b/core/assets-raw/sprites/ui/icon-folder-parent.png differ
diff --git a/core/assets-raw/sprites/ui/icon-folder.png b/core/assets-raw/sprites/ui/icon-folder.png
new file mode 100755
index 0000000000..6d9471196b
Binary files /dev/null and b/core/assets-raw/sprites/ui/icon-folder.png differ
diff --git a/core/assets-raw/sprites/ui/icon-home.png b/core/assets-raw/sprites/ui/icon-home.png
new file mode 100755
index 0000000000..087443880f
Binary files /dev/null and b/core/assets-raw/sprites/ui/icon-home.png differ
diff --git a/core/assets/sprites/sprites.atlas b/core/assets/sprites/sprites.atlas
index 5d792246a9..84e0e16d12 100644
--- a/core/assets/sprites/sprites.atlas
+++ b/core/assets/sprites/sprites.atlas
@@ -34,56 +34,56 @@ blocks/blackrockshadow1
index: -1
blocks/blackstone1
rotate: false
- xy: 635, 222
+ xy: 716, 267
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/blackstone2
rotate: false
- xy: 625, 174
+ xy: 716, 257
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/blackstone3
rotate: false
- xy: 733, 264
+ xy: 726, 269
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/blackstoneblock1
rotate: false
- xy: 728, 254
+ xy: 726, 259
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/blackstoneblock2
rotate: false
- xy: 728, 244
+ xy: 736, 264
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/blackstoneblock3
rotate: false
- xy: 728, 234
+ xy: 716, 247
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/blackstoneedge
rotate: false
- xy: 519, 201
+ xy: 521, 153
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
blocks/block
rotate: false
- xy: 738, 244
+ xy: 736, 254
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -118,112 +118,112 @@ blocks/chainturret-icon
index: -1
blocks/coal1
rotate: false
- xy: 743, 264
+ xy: 726, 239
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/coal2
rotate: false
- xy: 748, 254
+ xy: 736, 234
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/coal3
rotate: false
- xy: 748, 244
+ xy: 333, 91
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/coaldrill
rotate: false
- xy: 748, 234
+ xy: 343, 91
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/coalgenerator
rotate: false
- xy: 801, 454
+ xy: 353, 91
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/coalgenerator-top
rotate: false
- xy: 801, 444
+ xy: 363, 91
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/coalpurifier
rotate: false
- xy: 801, 434
+ xy: 373, 91
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/combustiongenerator
rotate: false
- xy: 801, 424
+ xy: 383, 91
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/compositewall
rotate: false
- xy: 797, 410
+ xy: 393, 95
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/conduit
rotate: false
- xy: 797, 400
+ xy: 403, 95
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/conduitbottom
rotate: false
- xy: 333, 91
+ xy: 413, 95
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/conduitliquid
rotate: false
- xy: 343, 91
+ xy: 423, 95
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/conduittop
rotate: false
- xy: 353, 91
+ xy: 433, 95
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/conveyor
rotate: false
- xy: 363, 91
+ xy: 443, 95
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/conveyormove
rotate: false
- xy: 373, 91
+ xy: 453, 95
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/conveyortunnel
rotate: false
- xy: 383, 91
+ xy: 463, 95
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -237,56 +237,56 @@ blocks/core
index: -1
blocks/cross
rotate: false
- xy: 393, 95
+ xy: 473, 95
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/crucible
rotate: false
- xy: 403, 95
+ xy: 483, 95
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/deepwater
rotate: false
- xy: 413, 95
+ xy: 813, 449
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/dirt1
rotate: false
- xy: 423, 95
+ xy: 813, 439
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/dirt2
rotate: false
- xy: 433, 95
+ xy: 813, 429
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/dirt3
rotate: false
- xy: 443, 95
+ xy: 813, 419
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/dirtedge
rotate: false
- xy: 519, 187
+ xy: 537, 169
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
blocks/door
rotate: false
- xy: 453, 95
+ xy: 592, 219
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -300,7 +300,7 @@ blocks/door-large
index: -1
blocks/door-large-icon
rotate: false
- xy: 463, 95
+ xy: 602, 222
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -314,21 +314,21 @@ blocks/door-large-open
index: -1
blocks/door-open
rotate: false
- xy: 473, 95
+ xy: 612, 222
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/doubleturret
rotate: false
- xy: 709, 279
+ xy: 833, 487
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/duriumwall
rotate: false
- xy: 483, 95
+ xy: 622, 222
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -342,266 +342,266 @@ blocks/duriumwall-large
index: -1
blocks/duriumwall-large-icon
rotate: false
- xy: 656, 222
+ xy: 632, 222
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/enemyspawn
rotate: false
- xy: 666, 222
+ xy: 269, 87
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/flameturret
rotate: false
- xy: 721, 281
+ xy: 845, 487
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/fluxpump
rotate: false
- xy: 649, 202
+ xy: 289, 87
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/grass1
rotate: false
- xy: 659, 212
+ xy: 299, 87
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/grass2
rotate: false
- xy: 649, 192
+ xy: 309, 87
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/grass3
rotate: false
- xy: 659, 202
+ xy: 319, 87
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/grassblock1
rotate: false
- xy: 659, 192
+ xy: 393, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/grassblock2
rotate: false
- xy: 669, 212
+ xy: 403, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/grassedge
rotate: false
- xy: 547, 201
+ xy: 709, 277
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
blocks/ice1
rotate: false
- xy: 669, 202
+ xy: 413, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/ice2
rotate: false
- xy: 669, 192
+ xy: 423, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/ice3
rotate: false
- xy: 676, 222
+ xy: 433, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/iceedge
rotate: false
- xy: 547, 187
+ xy: 656, 230
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
blocks/icerock1
rotate: false
- xy: 679, 212
+ xy: 443, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/icerock2
rotate: false
- xy: 679, 202
+ xy: 453, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/icerockshadow1
rotate: false
- xy: 679, 192
+ xy: 463, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/rockshadow1
rotate: false
- xy: 679, 192
+ xy: 463, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/icerockshadow2
rotate: false
- xy: 649, 182
+ xy: 473, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/rockshadow2
rotate: false
- xy: 649, 182
+ xy: 473, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/iron1
rotate: false
- xy: 309, 87
+ xy: 531, 129
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/iron2
rotate: false
- xy: 319, 87
+ xy: 529, 119
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/iron3
rotate: false
- xy: 393, 85
+ xy: 527, 109
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/irondrill
rotate: false
- xy: 403, 85
+ xy: 881, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/ironwall
rotate: false
- xy: 413, 85
+ xy: 891, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/junction
rotate: false
- xy: 423, 85
+ xy: 901, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/laserturret
rotate: false
- xy: 613, 184
+ xy: 749, 277
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/lava
rotate: false
- xy: 433, 85
+ xy: 911, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/lavaedge
rotate: false
- xy: 568, 213
+ xy: 670, 230
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
blocks/lavasmelter
rotate: false
- xy: 443, 85
+ xy: 921, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/liquiditemjunction
rotate: false
- xy: 453, 85
+ xy: 931, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/liquidjunction
rotate: false
- xy: 463, 85
+ xy: 941, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/liquidrouter
rotate: false
- xy: 473, 85
+ xy: 951, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/machineturret
rotate: false
- xy: 625, 184
+ xy: 575, 203
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/megarepairturret
rotate: false
- xy: 637, 210
+ xy: 575, 191
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/mortarturret
rotate: false
- xy: 637, 198
+ xy: 575, 179
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/mossblock
rotate: false
- xy: 493, 88
+ xy: 971, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/mossstone
rotate: false
- xy: 493, 88
+ xy: 971, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -622,7 +622,7 @@ blocks/nuclearreactor-center
index: -1
blocks/nuclearreactor-icon
rotate: false
- xy: 513, 90
+ xy: 991, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -643,329 +643,329 @@ blocks/nuclearreactor-small
index: -1
blocks/oil
rotate: false
- xy: 523, 90
+ xy: 1001, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/oiledge
rotate: false
- xy: 561, 199
+ xy: 723, 279
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
blocks/oilrefinery
rotate: false
- xy: 747, 291
+ xy: 749, 267
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/omnidrill
rotate: false
- xy: 745, 281
+ xy: 801, 413
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/plasmaturret
rotate: false
- xy: 637, 186
+ xy: 575, 167
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/playerspawn
rotate: false
- xy: 757, 291
+ xy: 800, 403
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/powerbooster
rotate: false
- xy: 755, 281
+ xy: 811, 409
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/poweredconveyor
rotate: false
- xy: 493, 78
+ xy: 810, 399
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/poweredconveyormove
rotate: false
- xy: 503, 78
+ xy: 602, 212
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/powerlaser
rotate: false
- xy: 513, 80
+ xy: 612, 212
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/powerlasercorner
rotate: false
- xy: 523, 80
+ xy: 622, 212
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/powerlaserrouter
rotate: false
- xy: 753, 271
+ xy: 632, 212
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/pulseconduit
rotate: false
- xy: 683, 233
+ xy: 599, 202
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/pulseconduitbottom
rotate: false
- xy: 693, 233
+ xy: 599, 192
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/pulseconduittop
rotate: false
- xy: 686, 223
+ xy: 609, 202
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/pump
rotate: false
- xy: 696, 223
+ xy: 599, 182
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/repairturret
rotate: false
- xy: 733, 274
+ xy: 580, 215
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/rock1
rotate: false
- xy: 689, 213
+ xy: 619, 202
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/rock2
rotate: false
- xy: 689, 203
+ xy: 599, 172
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/router
rotate: false
- xy: 689, 193
+ xy: 609, 182
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/rtgenerator
rotate: false
- xy: 689, 183
+ xy: 619, 192
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/rtgenerator-top
rotate: false
- xy: 699, 213
+ xy: 629, 202
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/sand1
rotate: false
- xy: 699, 203
+ xy: 609, 172
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/sand2
rotate: false
- xy: 699, 193
+ xy: 619, 182
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/sand3
rotate: false
- xy: 699, 183
+ xy: 629, 192
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/sandblock1
rotate: false
- xy: 716, 223
+ xy: 619, 172
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/sandblock2
rotate: false
- xy: 709, 213
+ xy: 629, 182
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/sandblock3
rotate: false
- xy: 709, 203
+ xy: 629, 172
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/sandedge
rotate: false
- xy: 561, 185
+ xy: 698, 229
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
blocks/shadow
rotate: false
- xy: 721, 269
+ xy: 704, 263
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/shieldgenerator
rotate: false
- xy: 709, 183
+ xy: 642, 208
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/shotgunturret
rotate: false
- xy: 716, 257
+ xy: 704, 251
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/shrub
rotate: false
- xy: 719, 193
+ xy: 639, 178
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/shrubshadow
rotate: false
- xy: 719, 183
+ xy: 639, 168
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/smelter
rotate: false
- xy: 726, 223
+ xy: 599, 162
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/sniperturret
rotate: false
- xy: 716, 245
+ xy: 587, 203
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/snow1
rotate: false
- xy: 736, 224
+ xy: 609, 162
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/snow2
rotate: false
- xy: 746, 224
+ xy: 619, 162
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/snow3
rotate: false
- xy: 729, 213
+ xy: 629, 162
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/snowblock1
rotate: false
- xy: 729, 203
+ xy: 639, 158
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/snowblock2
rotate: false
- xy: 729, 193
+ xy: 652, 218
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/snowblock3
rotate: false
- xy: 729, 183
+ xy: 652, 208
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/snowedge
rotate: false
- xy: 575, 199
+ xy: 805, 485
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
blocks/sorter
rotate: false
- xy: 739, 214
+ xy: 649, 198
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/steelconveyor
rotate: false
- xy: 739, 204
+ xy: 649, 188
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/steelconveyormove
rotate: false
- xy: 739, 194
+ xy: 649, 178
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/steelwall
rotate: false
- xy: 739, 184
+ xy: 649, 168
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -979,98 +979,98 @@ blocks/steelwall-large
index: -1
blocks/steelwall-large-icon
rotate: false
- xy: 749, 214
+ xy: 649, 158
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/stone1
rotate: false
- xy: 749, 204
+ xy: 662, 220
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/stone2
rotate: false
- xy: 749, 194
+ xy: 662, 210
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/stone3
rotate: false
- xy: 749, 184
+ xy: 672, 220
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/stoneblock1
rotate: false
- xy: 756, 224
+ xy: 672, 210
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/stoneblock2
rotate: false
- xy: 759, 214
+ xy: 682, 219
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/stoneblock3
rotate: false
- xy: 759, 204
+ xy: 692, 219
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/stonedrill
rotate: false
- xy: 759, 194
+ xy: 702, 219
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/stoneedge
rotate: false
- xy: 575, 185
+ xy: 805, 471
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
blocks/stoneformer
rotate: false
- xy: 759, 184
+ xy: 682, 209
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/stonewall
rotate: false
- xy: 519, 126
+ xy: 692, 209
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/teleporter
rotate: false
- xy: 519, 116
+ xy: 702, 209
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/teleporter-top
rotate: false
- xy: 625, 164
+ xy: 493, 78
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/thermalgenerator
rotate: false
- xy: 637, 176
+ xy: 503, 78
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -1084,56 +1084,56 @@ blocks/titancannon
index: -1
blocks/titancannon-icon
rotate: false
- xy: 716, 233
+ xy: 587, 191
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/titanium1
rotate: false
- xy: 635, 166
+ xy: 513, 80
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/titanium2
rotate: false
- xy: 647, 172
+ xy: 523, 80
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/titanium3
rotate: false
- xy: 657, 172
+ xy: 1011, 479
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/titaniumdrill
rotate: false
- xy: 667, 172
+ xy: 746, 254
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/titaniumpurifier
rotate: false
- xy: 677, 172
+ xy: 746, 244
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/titaniumshieldwall
rotate: false
- xy: 645, 162
+ xy: 746, 234
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/titaniumwall
rotate: false
- xy: 655, 162
+ xy: 659, 198
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -1147,70 +1147,70 @@ blocks/titaniumwall-large
index: -1
blocks/titaniumwall-large-icon
rotate: false
- xy: 665, 162
+ xy: 659, 188
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/turret
rotate: false
- xy: 601, 172
+ xy: 587, 179
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
blocks/uranium1
rotate: false
- xy: 645, 152
+ xy: 659, 158
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/uranium2
rotate: false
- xy: 655, 152
+ xy: 669, 200
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/uranium3
rotate: false
- xy: 665, 152
+ xy: 669, 190
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/uraniumdrill
rotate: false
- xy: 675, 152
+ xy: 669, 180
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/water
rotate: false
- xy: 513, 70
+ xy: 669, 170
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
blocks/wateredge
rotate: false
- xy: 513, 100
+ xy: 819, 485
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
blocks/waveturret
rotate: false
- xy: 613, 172
+ xy: 587, 167
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
bullet
rotate: false
- xy: 738, 234
+ xy: 736, 244
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -1294,14 +1294,14 @@ enemies/targetenemy-t1
index: -1
enemies/enemy-t2
rotate: false
- xy: 533, 201
+ xy: 521, 139
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
enemies/enemy-t3
rotate: false
- xy: 533, 187
+ xy: 513, 100
size: 12, 12
orig: 12, 12
offset: 0, 0
@@ -1392,63 +1392,63 @@ enemies/healerenemy-t3
index: -1
enemies/mortarenemy-t1
rotate: false
- xy: 189, 89
+ xy: 731, 298
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
enemies/mortarenemy-t2
rotate: false
- xy: 205, 89
+ xy: 747, 301
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
enemies/mortarenemy-t3
rotate: false
- xy: 221, 89
+ xy: 524, 215
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
enemies/rapidenemy-t1
rotate: false
- xy: 237, 89
+ xy: 540, 215
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
enemies/rapidenemy-t2
rotate: false
- xy: 253, 89
+ xy: 519, 199
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
enemies/rapidenemy-t3
rotate: false
- xy: 731, 298
+ xy: 519, 183
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
enemies/tankenemy-t1
rotate: false
- xy: 747, 301
+ xy: 535, 199
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
enemies/tankenemy-t2
rotate: false
- xy: 524, 215
+ xy: 535, 183
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
enemies/tankenemy-t3
rotate: false
- xy: 540, 215
+ xy: 521, 167
size: 14, 14
orig: 14, 14
offset: 0, 0
@@ -1483,56 +1483,56 @@ enemyarrow
index: -1
icon-coal
rotate: false
- xy: 659, 182
+ xy: 483, 85
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
icon-dirium
rotate: false
- xy: 669, 182
+ xy: 493, 88
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
icon-iron
rotate: false
- xy: 679, 182
+ xy: 503, 88
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
icon-steel
rotate: false
- xy: 269, 87
+ xy: 513, 90
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
icon-stone
rotate: false
- xy: 279, 87
+ xy: 523, 90
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
icon-titanium
rotate: false
- xy: 289, 87
+ xy: 521, 129
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
icon-uranium
rotate: false
- xy: 299, 87
+ xy: 519, 119
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
laser
rotate: false
- xy: 596, 215
+ xy: 797, 406
size: 1, 12
orig: 1, 12
offset: 0, 0
@@ -1553,35 +1553,35 @@ laserfull
index: -1
mechs/mech-standard
rotate: false
- xy: 582, 215
+ xy: 684, 229
size: 12, 12
orig: 12, 12
offset: 0, 0
index: -1
shell
rotate: false
- xy: 709, 193
+ xy: 642, 218
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
shot
rotate: false
- xy: 719, 213
+ xy: 639, 198
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
shot-long
rotate: false
- xy: 719, 203
+ xy: 639, 188
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
titanshell
rotate: false
- xy: 675, 162
+ xy: 659, 178
size: 8, 8
orig: 8, 8
offset: 0, 0
@@ -1673,21 +1673,21 @@ ui/check-over
index: -1
ui/clear
rotate: false
- xy: 556, 215
+ xy: 819, 473
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/cursor
rotate: false
- xy: 645, 222
+ xy: 92, 88
size: 4, 4
orig: 4, 4
offset: 0, 0
index: -1
ui/icon-areaDelete
rotate: false
- xy: 733, 286
+ xy: 857, 487
size: 10, 10
orig: 10, 10
offset: 0, 0
@@ -1701,14 +1701,14 @@ ui/icon-arrow
index: -1
ui/icon-arrow-left
rotate: false
- xy: 656, 232
+ xy: 869, 487
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-arrow-right
rotate: false
- xy: 668, 232
+ xy: 805, 459
size: 10, 10
orig: 10, 10
offset: 0, 0
@@ -1750,21 +1750,21 @@ ui/icon-close-over
index: -1
ui/icon-crafting
rotate: false
- xy: 1012, 489
+ xy: 801, 447
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-cursor
rotate: false
- xy: 704, 263
+ xy: 801, 435
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-defense
rotate: false
- xy: 704, 251
+ xy: 801, 423
size: 10, 10
orig: 10, 10
offset: 0, 0
@@ -1778,7 +1778,7 @@ ui/icon-discord
index: -1
ui/icon-distribution
rotate: false
- xy: 704, 239
+ xy: 1012, 489
size: 10, 10
orig: 10, 10
offset: 0, 0
@@ -1790,6 +1790,20 @@ ui/icon-donate
orig: 14, 14
offset: 0, 0
index: -1
+ui/icon-file
+ rotate: false
+ xy: 640, 248
+ size: 14, 14
+ orig: 14, 14
+ offset: 0, 0
+ index: -1
+ui/icon-file-text
+ rotate: false
+ xy: 598, 232
+ size: 14, 14
+ orig: 14, 14
+ offset: 0, 0
+ index: -1
ui/icon-fill
rotate: false
xy: 742, 349
@@ -1797,30 +1811,51 @@ ui/icon-fill
orig: 16, 16
offset: 0, 0
index: -1
+ui/icon-folder
+ rotate: false
+ xy: 614, 232
+ size: 14, 14
+ orig: 14, 14
+ offset: 0, 0
+ index: -1
+ui/icon-folder-parent
+ rotate: false
+ xy: 630, 232
+ size: 14, 14
+ orig: 14, 14
+ offset: 0, 0
+ index: -1
ui/icon-hold
rotate: false
- xy: 589, 203
+ xy: 551, 203
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-holdDelete
rotate: false
- xy: 589, 191
+ xy: 551, 191
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
+ui/icon-home
+ rotate: false
+ xy: 693, 275
+ size: 14, 14
+ orig: 14, 14
+ offset: 0, 0
+ index: -1
ui/icon-info
rotate: false
- xy: 599, 220
+ xy: 551, 179
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-load
rotate: false
- xy: 640, 248
+ xy: 656, 260
size: 14, 14
orig: 14, 14
offset: 0, 0
@@ -1834,21 +1869,21 @@ ui/icon-loading
index: -1
ui/icon-menu
rotate: false
- xy: 611, 220
+ xy: 556, 215
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-none
rotate: false
- xy: 623, 220
+ xy: 568, 215
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-pause
rotate: false
- xy: 601, 208
+ xy: 563, 203
size: 10, 10
orig: 10, 10
offset: 0, 0
@@ -1869,35 +1904,35 @@ ui/icon-pick
index: -1
ui/icon-play
rotate: false
- xy: 601, 196
+ xy: 563, 191
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-play-2
rotate: false
- xy: 598, 232
+ xy: 672, 260
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
ui/icon-power
rotate: false
- xy: 613, 208
+ xy: 563, 179
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-production
rotate: false
- xy: 613, 196
+ xy: 551, 167
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-quit
rotate: false
- xy: 614, 232
+ xy: 656, 244
size: 14, 14
orig: 14, 14
offset: 0, 0
@@ -1911,77 +1946,77 @@ ui/icon-redo
index: -1
ui/icon-rotate
rotate: false
- xy: 630, 232
+ xy: 672, 244
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
ui/icon-rotate-arrow
rotate: false
- xy: 693, 275
+ xy: 688, 259
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
ui/icon-rotate-left
rotate: false
- xy: 656, 260
+ xy: 688, 243
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
ui/icon-rotate-right
rotate: false
- xy: 672, 260
+ xy: 189, 89
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
ui/icon-save
rotate: false
- xy: 656, 244
+ xy: 205, 89
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
ui/icon-settings
rotate: false
- xy: 625, 208
+ xy: 563, 167
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-terrain
rotate: false
- xy: 672, 244
+ xy: 221, 89
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
ui/icon-tools
rotate: false
- xy: 688, 259
+ xy: 237, 89
size: 14, 14
orig: 14, 14
offset: 0, 0
index: -1
ui/icon-touch
rotate: false
- xy: 625, 196
+ xy: 737, 286
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-touchDelete
rotate: false
- xy: 589, 179
+ xy: 749, 289
size: 10, 10
orig: 10, 10
offset: 0, 0
index: -1
ui/icon-tutorial
rotate: false
- xy: 688, 243
+ xy: 253, 89
size: 14, 14
orig: 14, 14
offset: 0, 0
@@ -1995,7 +2030,7 @@ ui/icon-undo
index: -1
ui/icon-weapon
rotate: false
- xy: 601, 184
+ xy: 737, 274
size: 10, 10
orig: 10, 10
offset: 0, 0
@@ -2079,7 +2114,7 @@ ui/selection
index: -1
ui/slider
rotate: false
- xy: 680, 234
+ xy: 746, 264
size: 1, 8
orig: 1, 8
offset: 0, 0
@@ -2107,7 +2142,7 @@ ui/slider-knob-over
index: -1
ui/slider-vertical
rotate: false
- xy: 706, 226
+ xy: 592, 216
size: 8, 1
orig: 8, 1
offset: 0, 0
@@ -2216,42 +2251,42 @@ ui/window-empty
index: -1
weapons/blaster
rotate: false
- xy: 738, 254
+ xy: 726, 249
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
weapons/flamer
rotate: false
- xy: 649, 212
+ xy: 279, 87
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
weapons/mortar
rotate: false
- xy: 483, 85
+ xy: 961, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
weapons/multigun
rotate: false
- xy: 503, 88
+ xy: 981, 485
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
weapons/railgun
rotate: false
- xy: 706, 229
+ xy: 609, 192
size: 8, 8
orig: 8, 8
offset: 0, 0
index: -1
weapons/triblaster
rotate: false
- xy: 635, 156
+ xy: 659, 168
size: 8, 8
orig: 8, 8
offset: 0, 0
diff --git a/core/assets/sprites/sprites.png b/core/assets/sprites/sprites.png
index ddfb6297ef..eced6084b0 100644
Binary files a/core/assets/sprites/sprites.png and b/core/assets/sprites/sprites.png differ
diff --git a/core/src/io/anuke/mindustry/Mindustry.java b/core/src/io/anuke/mindustry/Mindustry.java
index c5aa9ff0ff..91722e269e 100644
--- a/core/src/io/anuke/mindustry/Mindustry.java
+++ b/core/src/io/anuke/mindustry/Mindustry.java
@@ -13,6 +13,7 @@ import io.anuke.ucore.core.Inputs;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.function.Callable;
import io.anuke.ucore.modules.ModuleCore;
+import io.anuke.ucore.scene.ui.TextField;
public class Mindustry extends ModuleCore {
public static Callable donationsCallable;
@@ -22,6 +23,7 @@ public class Mindustry extends ModuleCore {
@Override public String format(Date date){ return "invalid date"; }
@Override public String format(int number){ return number + ""; }
@Override public void openLink(String link){ }
+ @Override public void addDialog(TextField field){}
};
//always initialize blocks in this order, otherwise there are ID errors
diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java
index 3475b4d695..dc1d181fec 100644
--- a/core/src/io/anuke/mindustry/core/UI.java
+++ b/core/src/io/anuke/mindustry/core/UI.java
@@ -23,6 +23,7 @@ import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.mindustry.world.blocks.types.Configurable;
import io.anuke.ucore.core.*;
+import io.anuke.ucore.function.Listenable;
import io.anuke.ucore.function.VisibilityProvider;
import io.anuke.ucore.modules.SceneModule;
import io.anuke.ucore.scene.Element;
@@ -469,4 +470,16 @@ public class UI extends SceneModule{
((HudFragment)hudfrag).updateItems();
}
+ public void showConfirm(String title, String text, Listenable confirmed){
+ FloatingDialog dialog = new FloatingDialog(title);
+ dialog.content().add(text).pad(4f).units(Unit.dp);
+ dialog.buttons().defaults().size(200f, 54f).pad(2f).units(Unit.dp);
+ dialog.buttons().addButton("Cancel", dialog::hide);
+ dialog.buttons().addButton("OK", () -> {
+ dialog.hide();
+ confirmed.listen();
+ });
+ dialog.show();
+ }
+
}
diff --git a/core/src/io/anuke/mindustry/input/AndroidInput.java b/core/src/io/anuke/mindustry/input/AndroidInput.java
index fb5185d0f8..cdf661ab46 100644
--- a/core/src/io/anuke/mindustry/input/AndroidInput.java
+++ b/core/src/io/anuke/mindustry/input/AndroidInput.java
@@ -119,6 +119,7 @@ public class AndroidInput extends InputHandler{
@Override
public void update(){
+ enableHold = player.breakMode == PlaceMode.holdDelete;
if(enableHold && player.recipe != null && Gdx.input.isTouched(0) && Mathf.near2d(lmousex, lmousey, Gdx.input.getX(0), Gdx.input.getY(0), Unit.dp.inPixels(50))
&& !ui.hasMouse()){
diff --git a/core/src/io/anuke/mindustry/input/PlaceMode.java b/core/src/io/anuke/mindustry/input/PlaceMode.java
index 64fbb35a0a..666b9cbab8 100644
--- a/core/src/io/anuke/mindustry/input/PlaceMode.java
+++ b/core/src/io/anuke/mindustry/input/PlaceMode.java
@@ -82,7 +82,7 @@ public enum PlaceMode{
holdDelete{
{
delete = true;
- shown = false;
+ shown = true;
}
public void draw(int tilex, int tiley, int endx, int endy){
diff --git a/core/src/io/anuke/mindustry/io/PlatformFunction.java b/core/src/io/anuke/mindustry/io/PlatformFunction.java
index 28a142b34c..32e19363cd 100644
--- a/core/src/io/anuke/mindustry/io/PlatformFunction.java
+++ b/core/src/io/anuke/mindustry/io/PlatformFunction.java
@@ -2,8 +2,11 @@ package io.anuke.mindustry.io;
import java.util.Date;
+import io.anuke.ucore.scene.ui.TextField;
+
public interface PlatformFunction{
public String format(Date date);
public String format(int number);
public void openLink(String link);
+ public void addDialog(TextField field);
}
diff --git a/core/src/io/anuke/mindustry/mapeditor/EditorTool.java b/core/src/io/anuke/mindustry/mapeditor/EditorTool.java
index edd1be18fc..15a59562d2 100644
--- a/core/src/io/anuke/mindustry/mapeditor/EditorTool.java
+++ b/core/src/io/anuke/mindustry/mapeditor/EditorTool.java
@@ -12,11 +12,19 @@ import io.anuke.mindustry.world.ColorMapper;
public enum EditorTool{
pencil{
+ {
+ edit = true;
+ }
+
public void touched(MapEditor editor, int x, int y){
editor.draw(x, y);
}
},
fill{
+ {
+ edit = true;
+ }
+
public void touched(MapEditor editor, int x, int y){
Pixmap pix = editor.pixmap();
@@ -63,6 +71,7 @@ public enum EditorTool{
}
},
zoom;
+ boolean edit;
public void touched(MapEditor editor, int x, int y){
diff --git a/core/src/io/anuke/mindustry/mapeditor/MapEditor.java b/core/src/io/anuke/mindustry/mapeditor/MapEditor.java
index 99021f5e35..b18831f1f6 100644
--- a/core/src/io/anuke/mindustry/mapeditor/MapEditor.java
+++ b/core/src/io/anuke/mindustry/mapeditor/MapEditor.java
@@ -84,13 +84,13 @@ public class MapEditor{
this.brushSize = 1;
if(map.pixmap == null){
pixmap = new Pixmap(256, 256, Format.RGB888);
- pixmap.setColor(ColorMapper.getColor(Blocks.stone));
+ pixmap.setColor(ColorMapper.getColor(drawBlock));
pixmap.fill();
texture = new Texture(pixmap);
}else{
pixmap = map.pixmap;
- pixmap.setColor(ColorMapper.getColor(Blocks.stone));
texture = map.texture;
+ pixmap.setColor(ColorMapper.getColor(drawBlock));
}
}
@@ -161,8 +161,24 @@ public class MapEditor{
return pixmap;
}
+ public void setPixmap(Pixmap out){
+ if(pixmap.getWidth() == out.getWidth() && pixmap.getHeight() == out.getHeight()){
+ pixmap.dispose();
+ pixmap = out;
+ texture.draw(out, 0, 0);
+ }else{
+ pixmap.dispose();
+ texture.dispose();
+ pixmap = out;
+ texture = new Texture(out);
+ }
+ pixmap.setColor(ColorMapper.getColor(drawBlock));
+ map.pixmap = pixmap;
+ map.texture = texture;
+ }
+
public void resize(int width, int height){
- Pixmap out = Pixmaps.resize(pixmap, width, height);
+ Pixmap out = Pixmaps.resize(pixmap, width, height, ColorMapper.getColor(Blocks.stone));
pixmap.dispose();
pixmap = out;
texture.dispose();
@@ -174,5 +190,6 @@ public class MapEditor{
filterPixmap = null;
filterTexture = null;
}
+ pixmap.setColor(ColorMapper.getColor(drawBlock));
}
}
diff --git a/core/src/io/anuke/mindustry/mapeditor/MapEditorDialog.java b/core/src/io/anuke/mindustry/mapeditor/MapEditorDialog.java
index 55e7bc36a2..8ba595d51b 100644
--- a/core/src/io/anuke/mindustry/mapeditor/MapEditorDialog.java
+++ b/core/src/io/anuke/mindustry/mapeditor/MapEditorDialog.java
@@ -1,8 +1,13 @@
package io.anuke.mindustry.mapeditor;
+import java.util.Arrays;
+
+import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
+import com.badlogic.gdx.graphics.Texture;
import io.anuke.mindustry.Vars;
+import io.anuke.mindustry.ui.FileChooser;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.ColorMapper;
import io.anuke.mindustry.world.ColorMapper.BlockPair;
@@ -12,6 +17,7 @@ import io.anuke.mindustry.world.blocks.SpecialBlocks;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.Timers;
+import io.anuke.ucore.graphics.Pixmaps;
import io.anuke.ucore.scene.builders.*;
import io.anuke.ucore.scene.ui.*;
import io.anuke.ucore.scene.ui.layout.Table;
@@ -24,6 +30,8 @@ public class MapEditorDialog extends Dialog{
private MapLoadDialog loadDialog;
private MapSaveDialog saveDialog;
private MapResizeDialog resizeDialog;
+ private FileChooser openFile, saveFile;
+ private boolean saved = false;
private ButtonGroup blockgroup;
@@ -33,8 +41,54 @@ public class MapEditorDialog extends Dialog{
dialog = new MapGenerateDialog(editor);
view = new MapView(editor);
+ openFile = new FileChooser("Load Image", FileChooser.pngFilter, true, file -> {
+ Vars.ui.showLoading();
+ Timers.run(3f, () -> {
+ try{
+ Pixmap pixmap = new Pixmap(file);
+ if(verifySize(pixmap)){
+ editor.setPixmap(pixmap);
+ }else{
+ Vars.ui.showError("[orange]Invalid image dimensions![]\nValid map dimensions: " + Arrays.toString(MapEditor.validMapSizes));
+ }
+ }catch (Exception e){
+ Vars.ui.showError("Error loading image file!");
+ e.printStackTrace();
+ }
+ Vars.ui.hideLoading();
+ });
+ });
+
+ saveFile = new FileChooser("Save Image", false, file -> {
+ if(!file.extension().toLowerCase().equals(".png")){
+ file = file.parent().child(file.nameWithoutExtension() + ".png");
+ }
+ FileHandle result = file;
+ Vars.ui.showLoading();
+ Timers.run(3f, () -> {
+ try{
+ Pixmaps.write(editor.pixmap(), result);
+ }catch (Exception e){
+ Vars.ui.showError("Error saving image file!");
+ e.printStackTrace();
+ }
+ Vars.ui.hideLoading();
+ });
+ });
+
loadDialog = new MapLoadDialog(map -> {
- editor.beginEdit(map);
+ saveDialog.setFieldText(map.name);
+ Vars.ui.showLoading();
+
+ Timers.run(3f, () -> {
+ Map copy = new Map();
+ copy.name = map.name;
+ copy.id = -1;
+ copy.pixmap = Pixmaps.copy(map.pixmap);
+ copy.texture = new Texture(copy.pixmap);
+ editor.beginEdit(copy);
+ Vars.ui.hideLoading();
+ });
});
resizeDialog = new MapResizeDialog(editor, (x, y) -> {
@@ -51,6 +105,7 @@ public class MapEditorDialog extends Dialog{
saveDialog = new MapSaveDialog(name -> {
Vars.ui.showLoading();
if(verifyMap()){
+ saved = true;
editor.getMap().name = name;
Timers.run(10f, () -> {
Vars.world.maps().saveAndReload(editor.getMap(), editor.pixmap());
@@ -70,11 +125,16 @@ public class MapEditorDialog extends Dialog{
build.end();
shown(() -> {
+ saved = true;
editor.beginEdit(new Map());
Core.scene.setScrollFocus(view);
});
}
+ public void resetSaved(){
+ saved = false;
+ }
+
public void updateSelectedBlock(){
Block block = editor.getDrawBlock();
int i = 0;
@@ -103,6 +163,12 @@ public class MapEditorDialog extends Dialog{
row();
+ new imagebutton("icon-cursor", 10f*3f, () -> {
+ resizeDialog.show();
+ }).text("resize").padTop(4f);
+
+ row();
+
new imagebutton("icon-load", isize, () -> {
loadDialog.show();
}).text("load map");
@@ -116,25 +182,23 @@ public class MapEditorDialog extends Dialog{
row();
new imagebutton("icon-load", isize, () -> {
-
+ openFile.show();
}).text("load image");
row();
new imagebutton("icon-save", isize, () -> {
-
+ saveFile.show();
}).text("save image");
row();
- new imagebutton("icon-cursor", 10f*3f, () -> {
- resizeDialog.show();
- }).text("resize").padTop(4f);
-
- row();
-
new imagebutton("icon-arrow-left", isize, () -> {
- hide();
+ if(!saved){
+ Vars.ui.showConfirm("Confirm Exit", "[scarlet]You have unsaved changes![]\nAre you sure you want to exit?", () -> hide());
+ }else{
+ hide();
+ }
}).padBottom(0).text("back");
}}.left().growY().end();
@@ -186,6 +250,18 @@ public class MapEditorDialog extends Dialog{
}}.grow().end();
}
+ private boolean verifySize(Pixmap pix){
+ boolean w = false, h = false;
+ for(int i : MapEditor.validMapSizes){
+ if(pix.getWidth() == i)
+ w = true;
+ if(pix.getHeight() == i)
+ h = true;
+ }
+
+ return w && h;
+ }
+
private boolean verifyMap(){
int psc = ColorMapper.getColor(SpecialBlocks.playerSpawn);
int esc = ColorMapper.getColor(SpecialBlocks.enemySpawn);
@@ -221,6 +297,7 @@ public class MapEditorDialog extends Dialog{
private void addBlockSelection(Table table){
Table content = new Table();
ScrollPane pane = new ScrollPane(content, "volume");
+ pane.setScrollingDisabled(true, false);
pane.setFadeScrollBars(false);
pane.setOverscroll(true, false);
ButtonGroup group = new ButtonGroup<>();
@@ -242,10 +319,12 @@ public class MapEditorDialog extends Dialog{
}
}
- group.getButtons().get(3).setChecked(true);
+ content.padLeft(Unit.dp.inPixels(-5f));
+
+ group.getButtons().get(2).setChecked(true);
Table extra = new Table("button");
- extra.addWrap(() -> editor.getDrawBlock().name).width(120f).center();
+ extra.labelWrap(() -> editor.getDrawBlock().name).width(120f).center();
table.add(extra).growX();
table.row();
table.add(pane).growY().fillX();
diff --git a/core/src/io/anuke/mindustry/mapeditor/MapGenerateDialog.java b/core/src/io/anuke/mindustry/mapeditor/MapGenerateDialog.java
index cf3865018b..7b91138b85 100644
--- a/core/src/io/anuke/mindustry/mapeditor/MapGenerateDialog.java
+++ b/core/src/io/anuke/mindustry/mapeditor/MapGenerateDialog.java
@@ -4,6 +4,7 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Scaling;
+import io.anuke.mindustry.Vars;
import io.anuke.mindustry.mapeditor.MapFilter.GenPref;
import io.anuke.mindustry.ui.BorderImage;
import io.anuke.mindustry.ui.FloatingDialog;
@@ -70,9 +71,15 @@ public class MapGenerateDialog extends FloatingDialog{
buttons().addButton("Update", () ->{
apply();
});
- buttons().addButton("Apply", () ->{
- editor.applyFilter();
- hide();
+ buttons().addButton("Apply", () ->{
+ Vars.ui.showLoading();
+
+ Timers.run(3f, () ->{
+ editor.applyFilter();
+ Vars.ui.hideLoading();
+ Vars.ui.getEditorDialog().resetSaved();
+ hide();
+ });
});
shown(() ->{
diff --git a/core/src/io/anuke/mindustry/mapeditor/MapResizeDialog.java b/core/src/io/anuke/mindustry/mapeditor/MapResizeDialog.java
index 82244f6db5..ef054b379c 100644
--- a/core/src/io/anuke/mindustry/mapeditor/MapResizeDialog.java
+++ b/core/src/io/anuke/mindustry/mapeditor/MapResizeDialog.java
@@ -16,6 +16,7 @@ public class MapResizeDialog extends FloatingDialog{
public MapResizeDialog(MapEditor editor, BiConsumer cons){
super("resize map");
shown(() -> {
+ content().clear();
Pixmap pix = editor.pixmap();
width = pix.getWidth();
height = pix.getHeight();
@@ -48,7 +49,7 @@ public class MapResizeDialog extends FloatingDialog{
table.row();
}
- content().add(() ->
+ content().label(() ->
width + height > 512 ? "[scarlet]Warning!\n[]Maps larger than 256 units may be laggy and unstable." : ""
).get().setAlignment(Align.center, Align.center);
content().row();
diff --git a/core/src/io/anuke/mindustry/mapeditor/MapSaveDialog.java b/core/src/io/anuke/mindustry/mapeditor/MapSaveDialog.java
index b54f05600b..3b366b8adc 100644
--- a/core/src/io/anuke/mindustry/mapeditor/MapSaveDialog.java
+++ b/core/src/io/anuke/mindustry/mapeditor/MapSaveDialog.java
@@ -17,7 +17,7 @@ public class MapSaveDialog extends FloatingDialog{
shown(() -> {
content().clear();
- content().add(() ->{
+ content().label(() ->{
Map map = Vars.world.maps().getMap(field.getText());
if(map != null){
if(map.custom){
@@ -47,6 +47,11 @@ public class MapSaveDialog extends FloatingDialog{
buttons().add(button);
}
+ public void setFieldText(String text){
+ field.setText(text);
+ }
+
+
private boolean invalid(){
if(field.getText().isEmpty()){
return true;
diff --git a/core/src/io/anuke/mindustry/mapeditor/MapView.java b/core/src/io/anuke/mindustry/mapeditor/MapView.java
index 87b764af07..8cc03e1733 100644
--- a/core/src/io/anuke/mindustry/mapeditor/MapView.java
+++ b/core/src/io/anuke/mindustry/mapeditor/MapView.java
@@ -11,12 +11,11 @@ import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars;
-import io.anuke.ucore.core.Core;
-import io.anuke.ucore.core.Draw;
-import io.anuke.ucore.core.Inputs;
+import io.anuke.ucore.core.*;
import io.anuke.ucore.scene.Element;
import io.anuke.ucore.scene.event.InputEvent;
import io.anuke.ucore.scene.event.InputListener;
+import io.anuke.ucore.scene.event.Touchable;
import io.anuke.ucore.scene.ui.layout.Unit;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Tmp;
@@ -36,6 +35,7 @@ public class MapView extends Element implements GestureListener{
this.editor = editor;
Inputs.addProcessor(0, new GestureDetector(20, 0.5f, 2, 0.15f, this));
+ setTouchable(Touchable.enabled);
addListener(new InputListener(){
int lastx, lasty;
@@ -48,6 +48,10 @@ public class MapView extends Element implements GestureListener{
lasty = p.y;
tool.touched(editor, p.x, p.y);
+ if(tool.edit){
+ Vars.ui.getEditorDialog().resetSaved();
+ }
+
drawing = true;
return true;
}
@@ -62,6 +66,7 @@ public class MapView extends Element implements GestureListener{
GridPoint2 p = project(x, y);
if(drawing && tool == EditorTool.pencil){
+ Vars.ui.getEditorDialog().resetSaved();
Array points = br.line(lastx, lasty, p.x, p.y);
for(GridPoint2 point : points){
editor.draw(point.x, point.y);
@@ -71,20 +76,6 @@ public class MapView extends Element implements GestureListener{
lasty = p.y;
}
});
-
- addListener(new InputListener(){
- @Override
- public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
- return tool == EditorTool.zoom;
- }
-
-
- @Override
- public void touchDragged (InputEvent event, float x, float y, int pointer) {
- //offsetx += Gdx.input.getDeltaX(pointer) / zoom;
- //offsety -= Gdx.input.getDeltaY(pointer) / zoom;
- }
- });
}
@Override
@@ -106,23 +97,28 @@ public class MapView extends Element implements GestureListener{
}
private GridPoint2 project(float x, float y){
- float size = Math.min(width, height)*zoom;
- x = (x - getWidth()/2 + size/2 - offsetx*zoom) / size * editor.texture().getWidth();
- y = (y - getHeight()/2 + size/2 - offsety*zoom) / size * editor.texture().getHeight();
+ float ratio = 1f / ((float)editor.pixmap().getWidth() / editor.pixmap().getHeight());
+ float size = Math.min(width, height);
+ float sclwidth = size * zoom;
+ float sclheight = size * zoom * ratio;
+ x = (x - getWidth()/2 + sclwidth/2 - offsetx*zoom) / sclwidth * editor.texture().getWidth();
+ y = (y - getHeight()/2 + sclheight/2 - offsety*zoom) / sclheight * editor.texture().getHeight();
return Tmp.g1.set((int)x, editor.texture().getHeight() - 1 - (int)y);
}
@Override
public void draw(Batch batch, float alpha){
+ float ratio = 1f / ((float)editor.pixmap().getWidth() / editor.pixmap().getHeight());
float size = Math.min(width, height);
- float sclsize = size * zoom;
+ float sclwidth = size * zoom;
+ float sclheight = size * zoom * ratio;
float centerx = x + width/2 + offsetx * zoom;
float centery = y + height/2 + offsety * zoom;
batch.flush();
boolean pop = ScissorStack.pushScissors(Tmp.r1.set(x + width/2 - size/2, y + height/2 - size/2, size, size));
- batch.draw(editor.texture(), centerx - sclsize/2, centery - sclsize/2, sclsize, sclsize);
+ batch.draw(editor.texture(), centerx - sclwidth/2, centery - sclheight/2, sclwidth, sclheight);
batch.flush();
if(pop) ScissorStack.popScissors();
@@ -134,7 +130,10 @@ public class MapView extends Element implements GestureListener{
}
private boolean active(){
- return Core.scene.getKeyboardFocus() != null && Core.scene.getKeyboardFocus().isDescendantOf(Vars.ui.getEditorDialog()) && Vars.ui.isEditing() && tool == EditorTool.zoom;
+ return Core.scene.getKeyboardFocus() != null
+ && Core.scene.getKeyboardFocus().isDescendantOf(Vars.ui.getEditorDialog())
+ && Vars.ui.isEditing() && tool == EditorTool.zoom &&
+ Core.scene.hit(Graphics.mouse().x, Graphics.mouse().y, true) == this;
}
@Override
diff --git a/core/src/io/anuke/mindustry/ui/FileChooser.java b/core/src/io/anuke/mindustry/ui/FileChooser.java
new file mode 100644
index 0000000000..4a063f85ab
--- /dev/null
+++ b/core/src/io/anuke/mindustry/ui/FileChooser.java
@@ -0,0 +1,337 @@
+package io.anuke.mindustry.ui;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.Arrays;
+import java.util.Comparator;
+
+import com.badlogic.gdx.Gdx;
+import com.badlogic.gdx.files.FileHandle;
+import com.badlogic.gdx.graphics.g2d.GlyphLayout;
+import com.badlogic.gdx.utils.Align;
+import com.badlogic.gdx.utils.Array;
+import com.badlogic.gdx.utils.Pools;
+
+import io.anuke.mindustry.Mindustry;
+import io.anuke.ucore.core.Core;
+import io.anuke.ucore.function.Consumer;
+import io.anuke.ucore.function.Predicate;
+import io.anuke.ucore.scene.event.Touchable;
+import io.anuke.ucore.scene.ui.*;
+import io.anuke.ucore.scene.ui.layout.Table;
+import io.anuke.ucore.scene.ui.layout.Unit;
+
+public class FileChooser extends FloatingDialog{
+
+ private Table files;
+ private FileHandle homeDirectory = Gdx.files.local(Gdx.files.getExternalStoragePath());
+ private FileHandle directory = homeDirectory;
+ private ScrollPane pane;
+ private TextField navigation, filefield;
+ private TextButton ok;
+ private FileHistory stack = new FileHistory();
+ private Predicate filter;
+ private Consumer selectListener;
+ private boolean open;
+
+ public FileChooser(String title, boolean open, Consumer result){
+ this(title, defaultFilter, open, result);
+ }
+
+ public FileChooser(String title, Predicate filter, boolean open, Consumer result){
+ super(title);
+ this.open = open;
+ this.filter = filter;
+ this.selectListener = result;
+ setupWidgets();
+ }
+
+ private void setupWidgets(){
+ getCell(content()).maxWidth(Gdx.graphics.getWidth()/2);
+ content().pad(-Unit.dp.inPixels(10));
+
+ Table content = new Table();
+
+ filefield = new TextField();
+ if(!open) Mindustry.platforms.addDialog(filefield);
+ filefield.setDisabled(open);
+
+ ok = new TextButton(open ? "Open" : "Save");
+
+ ok.clicked(() -> {
+ if(ok.isDisabled()) return;
+ if(selectListener != null)
+ selectListener.accept(directory.child(filefield.getText()));
+ hide();
+ });
+
+ filefield.changed(() -> {
+ ok.setDisabled(filefield.getText().replace(" ", "").isEmpty());
+ });
+
+ filefield.change();
+
+ TextButton cancel = new TextButton("Cancel");
+ cancel.clicked(() -> hide());
+
+ navigation = new TextField("");
+ navigation.setTouchable(Touchable.disabled);
+
+ files = new Table();
+
+ pane = new ScrollPane(files){
+ public float getPrefHeight(){
+ return Gdx.graphics.getHeight();
+ }
+ };
+ pane.setOverscroll(false, false);
+ pane.setFadeScrollBars(false);
+
+ updateFiles(true);
+
+ Table icontable = new Table();
+
+ float isize = Unit.dp.inPixels(14*2);
+
+ ImageButton up = new ImageButton("icon-folder-parent");
+ up.resizeImage(isize);
+ up.clicked(()->{
+ directory = directory.parent();
+ updateFiles(true);
+ });
+
+ ImageButton back = new ImageButton("icon-arrow-left");
+ back.resizeImage(isize);
+
+ ImageButton forward = new ImageButton("icon-arrow-right");
+ forward.resizeImage(isize);
+
+ forward.clicked(()-> stack.forward());
+
+ back.clicked(()-> stack.back());
+
+ ImageButton home = new ImageButton("icon-home");
+ home.resizeImage(isize);
+ home.clicked(()->{
+ directory = homeDirectory;
+ updateFiles(true);
+ });
+
+ icontable.defaults().height(50).growX().uniform();
+ icontable.add(home);
+ icontable.add(back);
+ icontable.add(forward);
+ icontable.add(up);
+
+ Table fieldcontent = new Table();
+ fieldcontent.bottom().left().add(new Label("File Name:"));
+ fieldcontent.add(filefield).height(40f).fillX().expandX().padLeft(10f);
+
+ Table buttons = new Table();
+ buttons.defaults().growX().height(50);
+ buttons.add(cancel);
+ buttons.add(ok);
+
+ content.top().left();
+ content.add(icontable).expandX().fillX();
+ content.row();
+
+ //content.add(navigation).colspan(3).left().padBottom(10f).expandX().fillX().height(40f);
+ //content.row();
+
+ content.center().add(pane).width(Gdx.graphics.getWidth()/2).colspan(3).units(Unit.px).grow();
+ content.row();
+
+ if(!open){
+ content.bottom().left().add(fieldcontent).colspan(3).grow().padTop(-2).padBottom(2);
+ content.row();
+ }
+
+ content.add(buttons).growX();
+
+ content().add(content);
+ //content().add(icontable).expandY().top();
+ }
+
+ private void updateFileFieldStatus(){
+ if(!open){
+ ok.setDisabled(filefield.getText().replace(" ", "").isEmpty());
+ }else{
+ ok.setDisabled(!directory.child(filefield.getText()).exists() || directory.child(filefield.getText()).isDirectory());
+ }
+ }
+
+ private FileHandle[] getFileNames(){
+ FileHandle[] handles = directory.list(new FileFilter(){
+ @Override
+ public boolean accept(File file){
+ return !file.getName().startsWith(".");
+ }
+ });
+
+ Arrays.sort(handles, new Comparator(){
+ @Override
+ public int compare(FileHandle a, FileHandle b){
+ if(a.isDirectory() && !b.isDirectory()) return -1;
+ if( !a.isDirectory() && b.isDirectory()) return 1;
+ return a.name().compareTo(b.name());
+ }
+ });
+ return handles;
+ }
+
+ private void updateFiles(boolean push){
+ if(push) stack.push(directory);
+ navigation.setText(directory.toString());
+
+ GlyphLayout layout = Pools.obtain(GlyphLayout.class);
+
+ layout.setText(Core.font, navigation.getText());
+
+ if(layout.width < navigation.getWidth()){
+ navigation.setCursorPosition(0);
+ }else{
+ navigation.setCursorPosition(navigation.getText().length());
+ }
+
+ Pools.free(layout);
+
+ files.clearChildren();
+ FileHandle[] names = getFileNames();
+
+ Image upimage = new Image("icon-folder-parent");
+
+ TextButton upbutton = new TextButton(".." + directory.toString());
+ upbutton.clicked(()->{
+ directory = directory.parent();
+ updateFiles(true);
+ });
+
+ upbutton.left().add(upimage).padRight(4f).size(14*2);
+ upbutton.getCells().reverse();
+
+ files.top().left().add(upbutton).align(Align.topLeft).fillX().expandX().height(50).pad(2).colspan(2);
+ upbutton.getLabel().setAlignment(Align.left);
+
+ files.row();
+
+ ButtonGroup group = new ButtonGroup();
+ group.setMinCheckCount(0);
+
+ for(FileHandle file : names){
+ if( !file.isDirectory() && !filter.test(file)) continue; //skip non-filtered files
+
+ String filename = file.name();
+
+ TextButton button = new TextButton(shorten(filename), "toggle");
+ group.add(button);
+
+ button.clicked(()->{
+ if( !file.isDirectory()){
+ filefield.setText(filename);
+ updateFileFieldStatus();
+ }else{
+ directory = directory.child(filename);
+ updateFiles(true);
+ }
+ });
+
+ filefield.changed(()->{
+ button.setChecked(filename.equals(filefield.getText()));
+ });
+
+ Image image = new Image(file.isDirectory() ? "icon-folder" : "icon-file-text");
+
+ button.add(image).padRight(4f).size(14*2f);
+ button.getCells().reverse();
+ files.top().left().add(button).align(Align.topLeft).fillX().expandX()
+ .height(50).pad(2).padTop(0).padBottom(0).colspan(2);
+ button.getLabel().setAlignment(Align.left);
+ files.row();
+ }
+
+ pane.setScrollY(0f);
+ updateFileFieldStatus();
+
+ if(open) filefield.clearText();
+ }
+
+ private String shorten(String string){
+ int max = 30;
+ if(string.length() <= max){
+ return string;
+ }else{
+ return string.substring(0, max - 3).concat("...");
+ }
+ }
+
+ @Override
+ public Dialog show(){
+ super.show();
+ Core.scene.setScrollFocus(pane);
+ return this;
+ }
+
+ public void fileSelected(Consumer listener){
+ this.selectListener = listener;
+ }
+
+ public class FileHistory{
+ private Array history = new Array();
+ private int index;
+
+ public FileHistory(){
+
+ }
+
+ public void push(FileHandle file){
+ if(index != history.size) history.truncate(index);
+ history.add(file);
+ index ++;
+ }
+
+ public void back(){
+ if( !canBack()) return;
+ index --;
+ directory = history.get(index - 1);
+ updateFiles(false);
+ }
+
+ public void forward(){
+ if( !canForward()) return;
+ directory = history.get(index);
+ index ++;
+ updateFiles(false);
+ }
+
+ public boolean canForward(){
+ return !(index >= history.size);
+ }
+
+ public boolean canBack(){
+ return !(index == 1) && index > 0;
+ }
+
+ void print(){
+
+ System.out.println("\n\n\n\n\n\n");
+ int i = 0;
+ for(FileHandle file : history){
+ i ++;
+ if(index == i){
+ System.out.println("[[" + file.toString() + "]]");
+ }else{
+ System.out.println("--" + file.toString() + "--");
+ }
+ }
+ }
+ }
+
+ public static interface FileHandleFilter{
+ public boolean accept(FileHandle file);
+ }
+
+ public static Predicate pngFilter = file -> file.extension().equalsIgnoreCase("png");
+ public static Predicate jpegFilter = file -> file.extension().equalsIgnoreCase("png") || file.extension().equalsIgnoreCase("jpg") || file.extension().equalsIgnoreCase("jpeg");
+ public static Predicate defaultFilter = file -> true;
+}
diff --git a/core/src/io/anuke/mindustry/ui/LevelDialog.java b/core/src/io/anuke/mindustry/ui/LevelDialog.java
index 837d6f8531..45d732e393 100644
--- a/core/src/io/anuke/mindustry/ui/LevelDialog.java
+++ b/core/src/io/anuke/mindustry/ui/LevelDialog.java
@@ -8,7 +8,6 @@ import io.anuke.mindustry.world.Map;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.core.Timers;
-import io.anuke.ucore.function.StringSupplier;
import io.anuke.ucore.scene.ui.*;
import io.anuke.ucore.scene.ui.layout.Stack;
import io.anuke.ucore.scene.ui.layout.Table;
@@ -18,6 +17,7 @@ import io.anuke.ucore.scene.utils.Elements;
public class LevelDialog extends FloatingDialog{
private Map selectedMap = Vars.world.maps().getMap(0);
private TextureRegion region = new TextureRegion();
+ private ScrollPane pane;
public LevelDialog(){
super("Level Select");
@@ -34,7 +34,7 @@ public class LevelDialog extends FloatingDialog{
void setup(){
Table maps = new Table();
- ScrollPane pane = new ScrollPane(maps);
+ pane = new ScrollPane(maps);
pane.setFadeScrollBars(false);
int maxwidth = 4;
@@ -66,7 +66,7 @@ public class LevelDialog extends FloatingDialog{
Table inset = new Table("pane-button");
inset.add("[accent]"+map.name).pad(3f).units(Unit.dp);
inset.row();
- inset.add((StringSupplier)(()->"High Score: [accent]" + Settings.getInt("hiscore" + map.name)))
+ inset.label((() -> "High Score: [accent]" + Settings.getInt("hiscore" + map.name)))
.pad(3f).units(Unit.dp);
inset.pack();
@@ -80,7 +80,21 @@ public class LevelDialog extends FloatingDialog{
ImageButton image = new ImageButton(new TextureRegion(map.texture), "togglemap");
image.row();
image.add(inset).width(images+6).units(Unit.dp);
+ TextButton[] delete = new TextButton[1];
+ if(map.custom){
+ image.row();
+ delete[0] = image.addButton("Delete", () -> {
+ Vars.ui.showConfirm("Confirm Delete", "Are you sure you want to delete\nthe map \"[orange]" + map.name + "[]\"?", () -> {
+ Vars.world.maps().removeMap(map);
+ reload();
+ Core.scene.setScrollFocus(pane);
+ });
+ }).width(images+16).units(Unit.dp).padBottom(-10f).grow().get();
+ }
image.clicked(()->{
+ if(delete[0] != null && delete[0].getClickListener().isOver()){
+ return;
+ }
selectedMap = map;
hide();
Vars.control.playMap(selectedMap);
@@ -90,7 +104,7 @@ public class LevelDialog extends FloatingDialog{
stack.add(back);
stack.add(image);
- maps.add(stack).width(170).pad(4f).units(Unit.dp);
+ maps.add(stack).width(170).top().pad(4f).units(Unit.dp);
maps.padRight(Unit.dp.inPixels(26));
diff --git a/core/src/io/anuke/mindustry/world/Maps.java b/core/src/io/anuke/mindustry/world/Maps.java
index d9b3cb5599..0fc6f0644d 100644
--- a/core/src/io/anuke/mindustry/world/Maps.java
+++ b/core/src/io/anuke/mindustry/world/Maps.java
@@ -51,6 +51,18 @@ public class Maps implements Disposable{
}
}
+ public void removeMap(Map map){
+ maps.remove(map.id);
+ mapNames.remove(map.name);
+ Array