diff --git a/core/src/mindustry/core/Platform.java b/core/src/mindustry/core/Platform.java index 60d938f084..7e3bbde613 100644 --- a/core/src/mindustry/core/Platform.java +++ b/core/src/mindustry/core/Platform.java @@ -14,6 +14,7 @@ import mindustry.type.*; import mindustry.ui.dialogs.*; import rhino.*; +import java.io.*; import java.net.*; import static mindustry.Vars.*; @@ -140,6 +141,61 @@ public interface Platform{ * @param title The title of the native dialog */ default void showFileChooser(boolean open, String title, String extension, Cons cons){ + if(OS.isLinux && !OS.isAndroid){ + showZenity(open, title, new String[]{extension}, cons, () -> defaultFileDialog(open, title, extension, cons)); + }else{ + defaultFileDialog(open, title, extension, cons); + } + } + + /** attempt to use the native file picker with zenity, or runs the fallback Runnable if the operation fails */ + static void showZenity(boolean open, String title, String[] extensions, Cons cons, Runnable fallback){ + Threads.daemon(() -> { + try{ + String formatted = (title.startsWith("@") ? Core.bundle.get(title.substring(1)) : title).replaceAll("\"", "'"); + + String last = FileChooser.getLastDirectory().absolutePath(); + if(!last.endsWith("/")) last += "/"; + + //zenity doesn't support filtering by extension + Seq args = Seq.with("zenity", + "--file-selection", + "--title=" + formatted, + "--filename=" + last, + "--confirm-overwrite", + "--file-filter=" + Seq.with(extensions).toString(" ", s -> "*." + s), + "--file-filter=All files | *" //allow anything if the user wants + ); + + if(!open){ + args.add("--save"); + } + + String result = OS.exec(args.toArray(String.class)); + + if(result.isEmpty() || result.equals("\n")) return; + + if(result.endsWith("\n")) result = result.substring(0, result.length() - 1); + if(result.contains("\n")) throw new IOException("invalid input"); + + Fi file = Core.files.absolute(result); + Core.app.post(() -> { + FileChooser.setLastDirectory(file.isDirectory() ? file : file.parent()); + + if(!open){ + cons.get(file.parent().child(file.nameWithoutExtension() + "." + extensions[0])); + }else{ + cons.get(file); + } + }); + }catch(Exception e){ + Log.warn("zenity not found, using non-native file dialog. Consider installing `zenity` for native file dialogs."); + Core.app.post(fallback); + } + }); + } + + static void defaultFileDialog(boolean open, String title, String extension, Cons cons){ new FileChooser(title, file -> file.extEquals(extension), open, file -> { if(!open){ cons.get(file.parent().child(file.nameWithoutExtension() + "." + extension)); @@ -161,11 +217,17 @@ public interface Platform{ default void showMultiFileChooser(Cons cons, String... extensions){ if(mobile){ showFileChooser(true, extensions[0], cons); + }else if(OS.isLinux && !OS.isAndroid){ + showZenity(true, "@open", extensions, cons, () -> defaultMultiFileChooser(cons, extensions)); }else{ - new FileChooser("@open", file -> Structs.contains(extensions, file.extension().toLowerCase()), true, cons).show(); + defaultMultiFileChooser(cons, extensions); } } + static void defaultMultiFileChooser(Cons cons, String... extensions){ + new FileChooser("@open", file -> Structs.contains(extensions, file.extension().toLowerCase()), true, cons).show(); + } + /** Hide the app. Android only. */ default void hide(){ } diff --git a/core/src/mindustry/ui/dialogs/FileChooser.java b/core/src/mindustry/ui/dialogs/FileChooser.java index 8188d97514..6a33696fdc 100644 --- a/core/src/mindustry/ui/dialogs/FileChooser.java +++ b/core/src/mindustry/ui/dialogs/FileChooser.java @@ -20,7 +20,7 @@ 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 = lastDirectory; + Fi directory; private Table files; private ScrollPane pane; private TextField navigation, filefield; @@ -37,10 +37,7 @@ public class FileChooser extends BaseDialog{ this.filter = filter; this.selectListener = result; - if(!lastDirectory.exists()){ - lastDirectory = homeDirectory; - directory = lastDirectory; - } + directory = getLastDirectory(); onResize(() -> { cont.clear(); @@ -254,11 +251,18 @@ public class FileChooser extends BaseDialog{ if(open) filefield.clearText(); } - public static void setLastDirectory(Fi directory){ + 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 history = new Seq<>(); private int index;