Files
Mindustry/core/src/mindustry/ui/dialogs/FileChooser.java
2023-05-15 11:44:08 -04:00

305 lines
8.7 KiB
Java

package mindustry.ui.dialogs;
import arc.*;
import arc.files.*;
import arc.func.*;
import arc.graphics.g2d.*;
import arc.input.*;
import arc.scene.event.*;
import arc.scene.ui.*;
import arc.scene.ui.layout.*;
import arc.struct.*;
import arc.util.*;
import arc.util.pooling.*;
import mindustry.gen.*;
import mindustry.ui.*;
import java.util.*;
public class FileChooser extends BaseDialog{
private static final Fi homeDirectory = Core.files.absolute(Core.files.getExternalStoragePath());
static Fi lastDirectory = Core.files.absolute(Core.settings.getString("lastDirectory", homeDirectory.absolutePath()));
Fi directory;
private Table files;
private ScrollPane pane;
private TextField navigation, filefield;
private TextButton ok;
private FileHistory stack = new FileHistory();
private Boolf<Fi> filter;
private Cons<Fi> selectListener;
private boolean open;
public FileChooser(String title, Boolf<Fi> filter, boolean open, Cons<Fi> result){
super(title);
setFillParent(true);
this.open = open;
this.filter = filter;
this.selectListener = result;
directory = getLastDirectory();
onResize(() -> {
cont.clear();
setupWidgets();
});
shown(() -> {
cont.clear();
setupWidgets();
});
keyDown(KeyCode.enter, () -> {
ok.fireClick();
});
addCloseListener();
}
private void setupWidgets(){
cont.margin(-10);
Table content = new Table();
filefield = new TextField();
filefield.setOnlyFontChars(false);
if(!open) filefield.addInputDialog();
filefield.setDisabled(open);
ok = new TextButton(open ? "@load" : "@save");
ok.clicked(() -> {
if(ok.isDisabled()) return;
if(selectListener != null)
selectListener.get(directory.child(filefield.getText()));
hide();
});
filefield.changed(() -> {
ok.setDisabled(filefield.getText().replace(" ", "").isEmpty());
});
filefield.change();
TextButton cancel = new TextButton("@cancel");
cancel.clicked(this::hide);
navigation = new TextField("");
navigation.touchable = Touchable.disabled;
files = new Table();
files.marginRight(10);
files.marginLeft(3);
pane = new ScrollPane(files);
pane.setOverscroll(false, false);
pane.setFadeScrollBars(false);
updateFiles(true);
Table icontable = new Table();
ImageButton up = new ImageButton(Icon.upOpen);
up.clicked(() -> {
directory = directory.parent();
updateFiles(true);
});
ImageButton back = new ImageButton(Icon.left);
ImageButton forward = new ImageButton(Icon.right);
forward.clicked(() -> stack.forward());
back.clicked(() -> stack.back());
forward.setDisabled(() -> !stack.canForward());
back.setDisabled(() -> !stack.canBack());
ImageButton home = new ImageButton(Icon.home);
home.clicked(() -> {
directory = homeDirectory;
setLastDirectory(directory);
updateFiles(true);
});
icontable.defaults().height(60).growX().padTop(5).uniform();
icontable.add(home);
icontable.add(back);
icontable.add(forward);
icontable.add(up);
Table fieldcontent = new Table();
fieldcontent.bottom().left().add(new Label("@filename"));
fieldcontent.add(filefield).height(40f).fillX().expandX().padLeft(10f);
Table buttons = new Table();
buttons.defaults().growX().height(60);
buttons.add(cancel);
buttons.add(ok);
content.top().left();
content.add(icontable).expandX().fillX();
content.row();
content.center().add(pane).colspan(3).grow();
content.row();
if(!open){
content.bottom().left().add(fieldcontent).colspan(3).grow().padTop(-2).padBottom(2);
content.row();
}
content.add(buttons).growX();
cont.add(content).grow();
}
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 Fi[] getFileNames(){
Fi[] handles = directory.list(file -> !file.getName().startsWith("."));
Arrays.sort(handles, (a, b) -> {
if(a.isDirectory() && !b.isDirectory()) return -1;
if(!a.isDirectory() && b.isDirectory()) return 1;
return String.CASE_INSENSITIVE_ORDER.compare(a.name(), b.name());
});
return handles;
}
void updateFiles(boolean push){
if(push) stack.push(directory);
navigation.setText(directory.toString());
GlyphLayout layout = Pools.obtain(GlyphLayout.class, GlyphLayout::new);
layout.setText(Fonts.def, navigation.getText());
if(layout.width < navigation.getWidth()){
navigation.setCursorPosition(0);
}else{
navigation.setCursorPosition(navigation.getText().length());
}
Pools.free(layout);
files.clearChildren();
files.top().left();
Fi[] names = getFileNames();
Image upimage = new Image(Icon.upOpen);
TextButton upbutton = new TextButton(".." + directory.toString(), Styles.flatTogglet);
upbutton.clicked(() -> {
directory = directory.parent();
setLastDirectory(directory);
updateFiles(true);
});
upbutton.left().add(upimage).padRight(4f).padLeft(4);
upbutton.getLabel().setAlignment(Align.left);
upbutton.getCells().reverse();
files.add(upbutton).align(Align.topLeft).fillX().expandX().height(50).pad(2).colspan(2);
files.row();
ButtonGroup<TextButton> group = new ButtonGroup<>();
group.setMinCheckCount(0);
for(Fi file : names){
if(!file.isDirectory() && !filter.get(file)) continue; //skip non-filtered files
String filename = file.name();
TextButton button = new TextButton(filename.replace("[", "[["), Styles.flatTogglet);
button.getLabel().setWrap(false);
button.getLabel().setEllipsis(true);
group.add(button);
button.clicked(() -> {
if(!file.isDirectory()){
filefield.setText(filename);
updateFileFieldStatus();
}else{
directory = directory.child(filename);
setLastDirectory(directory);
updateFiles(true);
}
});
filefield.changed(() -> {
button.setChecked(filename.equals(filefield.getText()));
});
Image image = new Image(file.isDirectory() ? Icon.folder : Icon.fileText);
button.add(image).padRight(4f).padLeft(4);
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();
}
public static synchronized void setLastDirectory(Fi directory){
lastDirectory = directory;
Core.settings.put("lastDirectory", directory.absolutePath());
}
public static synchronized Fi getLastDirectory(){
if(!lastDirectory.exists()){
lastDirectory = homeDirectory;
}
return lastDirectory;
}
public class FileHistory{
private Seq<Fi> history = new Seq<>();
private int index;
public FileHistory(){
}
public void push(Fi file){
if(index != history.size) history.truncate(index);
history.add(file);
index++;
}
public void back(){
if(!canBack()) return;
index--;
directory = history.get(index - 1);
setLastDirectory(directory);
updateFiles(false);
}
public void forward(){
if(!canForward()) return;
directory = history.get(index);
setLastDirectory(directory);
index++;
updateFiles(false);
}
public boolean canForward(){
return !(index >= history.size);
}
public boolean canBack(){
return !(index == 1) && index > 0;
}
}
}