Finish all editor features
This commit is contained in:
337
core/src/io/anuke/mindustry/ui/FileChooser.java
Normal file
337
core/src/io/anuke/mindustry/ui/FileChooser.java
Normal file
@@ -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<FileHandle> filter;
|
||||
private Consumer<FileHandle> selectListener;
|
||||
private boolean open;
|
||||
|
||||
public FileChooser(String title, boolean open, Consumer<FileHandle> result){
|
||||
this(title, defaultFilter, open, result);
|
||||
}
|
||||
|
||||
public FileChooser(String title, Predicate<FileHandle> filter, boolean open, Consumer<FileHandle> 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<FileHandle>(){
|
||||
@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<TextButton> group = new ButtonGroup<TextButton>();
|
||||
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<FileHandle> listener){
|
||||
this.selectListener = listener;
|
||||
}
|
||||
|
||||
public class FileHistory{
|
||||
private Array<FileHandle> history = new Array<FileHandle>();
|
||||
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<FileHandle> pngFilter = file -> file.extension().equalsIgnoreCase("png");
|
||||
public static Predicate<FileHandle> jpegFilter = file -> file.extension().equalsIgnoreCase("png") || file.extension().equalsIgnoreCase("jpg") || file.extension().equalsIgnoreCase("jpeg");
|
||||
public static Predicate<FileHandle> defaultFilter = file -> true;
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
|
||||
Reference in New Issue
Block a user