package mindustry.ui.dialogs; import arc.*; import arc.struct.*; import arc.files.*; import arc.graphics.*; import arc.graphics.Texture.*; import arc.input.*; import arc.scene.*; import arc.scene.event.*; import arc.scene.ui.*; import arc.scene.ui.SettingsDialog.SettingsTable.*; import arc.scene.ui.TextButton.*; import arc.scene.ui.layout.*; import arc.util.*; import mindustry.core.GameState.*; import mindustry.core.*; import mindustry.game.EventType.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.input.*; import mindustry.ui.*; import static arc.Core.bundle; import static mindustry.Vars.*; public class SettingsMenuDialog extends SettingsDialog{ private SettingsTable graphics; private SettingsTable game; private SettingsTable sound; private Table prefs; private Table menu; private FloatingDialog dataDialog; private boolean wasPaused; public SettingsMenuDialog(){ hidden(() -> { Sounds.back.play(); if(!state.is(State.menu)){ if(!wasPaused || net.active()) state.set(State.playing); } }); shown(() -> { back(); if(!state.is(State.menu)){ wasPaused = state.is(State.paused); state.set(State.paused); } rebuildMenu(); }); setFillParent(true); title.setAlignment(Align.center); titleTable.row(); titleTable.add(new Image()).growX().height(3f).pad(4f).get().setColor(Pal.accent); cont.clearChildren(); cont.remove(); buttons.remove(); menu = new Table(Tex.button); game = new SettingsTable(); graphics = new SettingsTable(); sound = new SettingsTable(); prefs = new Table(); prefs.top(); prefs.margin(14f); rebuildMenu(); prefs.clearChildren(); prefs.add(menu); dataDialog = new FloatingDialog("$settings.data"); dataDialog.addCloseButton(); dataDialog.cont.table(Tex.button, t -> { t.defaults().size(270f, 60f).left(); TextButtonStyle style = Styles.cleart; t.addImageTextButton("$settings.cleardata", Icon.trash, style, () -> ui.showConfirm("$confirm", "$settings.clearall.confirm", () -> { ObjectMap map = new ObjectMap<>(); for(String value : Core.settings.keys()){ if(value.contains("usid") || value.contains("uuid")){ map.put(value, Core.settings.getString(value)); } } Core.settings.clear(); Core.settings.putAll(map); Core.settings.save(); for(Fi file : dataDirectory.list()){ file.deleteDirectory(); } Core.app.exit(); })); t.row(); t.addImageTextButton("$data.export", Icon.download, style, () -> { if(ios){ Fi file = Core.files.local("mindustry-data-export.zip"); try{ data.exportData(file); }catch(Exception e){ ui.showException(e); } platform.shareFile(file); }else{ platform.showFileChooser(false, "zip", file -> { try{ data.exportData(file); ui.showInfo("$data.exported"); }catch(Exception e){ e.printStackTrace(); ui.showException(e); } }); } }); t.row(); t.addImageTextButton("$data.import", Icon.download, style, () -> ui.showConfirm("$confirm", "$data.import.confirm", () -> platform.showFileChooser(true, "zip", file -> { try{ data.importData(file); Core.app.exit(); }catch(IllegalArgumentException e){ ui.showErrorMessage("$data.invalid"); }catch(Exception e){ e.printStackTrace(); if(e.getMessage() == null || !e.getMessage().contains("too short")){ ui.showException(e); }else{ ui.showErrorMessage("$data.invalid"); } } }))); if(!ios){ t.row(); t.addImageTextButton("$data.openfolder", Icon.folder, style, () -> Core.app.openFolder(Core.settings.getDataDirectory().absolutePath())); } }); ScrollPane pane = new ScrollPane(prefs); pane.addCaptureListener(new InputListener(){ @Override public boolean touchDown(InputEvent event, float x, float y, int pointer, KeyCode button){ Element actor = pane.hit(x, y, true); if(actor instanceof Slider){ pane.setFlickScroll(false); return true; } return super.touchDown(event, x, y, pointer, button); } @Override public void touchUp(InputEvent event, float x, float y, int pointer, KeyCode button){ pane.setFlickScroll(true); super.touchUp(event, x, y, pointer, button); } }); pane.setFadeScrollBars(false); row(); add(pane).grow().top(); row(); add(buttons).fillX(); addSettings(); } void rebuildMenu(){ menu.clearChildren(); TextButtonStyle style = Styles.cleart; menu.defaults().size(300f, 60f); menu.addButton("$settings.game", style, () -> visible(0)); menu.row(); menu.addButton("$settings.graphics", style, () -> visible(1)); menu.row(); menu.addButton("$settings.sound", style, () -> visible(2)); menu.row(); menu.addButton("$settings.language", style, ui.language::show); if(!mobile || Core.settings.getBool("keyboard")){ menu.row(); menu.addButton("$settings.controls", style, ui.controls::show); } menu.row(); menu.addButton("$settings.data", style, () -> dataDialog.show()); } void addSettings(){ sound.sliderPref("musicvol", bundle.get("setting.musicvol.name", "Music Volume"), 100, 0, 100, 1, i -> i + "%"); sound.sliderPref("sfxvol", bundle.get("setting.sfxvol.name", "SFX Volume"), 100, 0, 100, 1, i -> i + "%"); sound.sliderPref("ambientvol", bundle.get("setting.ambientvol.name", "Ambient Volume"), 100, 0, 100, 1, i -> i + "%"); game.screenshakePref(); if(mobile){ game.checkPref("autotarget", true); game.checkPref("keyboard", false, val -> control.setInput(val ? new DesktopInput() : new MobileInput())); if(Core.settings.getBool("keyboard")){ control.setInput(new DesktopInput()); } } //the issue with touchscreen support on desktop is that: //1) I can't test it //2) the SDL backend doesn't support multitouch /*else{ game.checkPref("touchscreen", false, val -> control.setInput(!val ? new DesktopInput() : new MobileInput())); if(Core.settings.getBool("touchscreen")){ control.setInput(new MobileInput()); } }*/ game.sliderPref("saveinterval", 60, 10, 5 * 120, 10, i -> Core.bundle.format("setting.seconds", i)); if(!mobile){ game.sliderPref("blockselecttimeout", 750, 0, 2000, 50, i -> Core.bundle.format("setting.milliseconds", i)); game.checkPref("crashreport", true); } game.checkPref("savecreate", true); game.checkPref("blockreplace", true); game.checkPref("conveyorpathfinding", true); game.checkPref("coreselect", false); game.checkPref("hints", true); if(!mobile){ game.checkPref("buildautopause", false); } if(steam && !Version.modifier.contains("beta")){ game.checkPref("publichost", false, i -> { platform.updateLobby(); }); } game.pref(new Setting(){ @Override public void add(SettingsTable table){ table.addButton("$tutorial.retake", () -> { hide(); control.playTutorial(); }).size(220f, 60f).pad(6).left(); table.add(); table.row(); hide(); } }); graphics.sliderPref("uiscale", 100, 25, 300, 25, s -> { if(ui.settings != null){ Core.settings.put("uiscalechanged", true); } return s + "%"; }); graphics.sliderPref("fpscap", 240, 15, 245, 5, s -> (s > 240 ? Core.bundle.get("setting.fpscap.none") : Core.bundle.format("setting.fpscap.text", s))); graphics.sliderPref("chatopacity", 100, 0, 100, 5, s -> s + "%"); graphics.sliderPref("lasersopacity", 100, 0, 100, 5, s -> { if(ui.settings != null){ Core.settings.put("preferredlaseropacity", s); } return s + "%"; }); graphics.sliderPref("bridgeopacity", 75, 0, 100, 5, s -> s + "%"); if(!mobile){ graphics.checkPref("vsync", true, b -> Core.graphics.setVSync(b)); graphics.checkPref("fullscreen", false, b -> { if(b){ Core.graphics.setFullscreenMode(Core.graphics.getDisplayMode()); }else{ Core.graphics.setWindowedMode(Core.graphics.getWidth(), Core.graphics.getHeight()); } }); graphics.checkPref("borderlesswindow", false, b -> Core.graphics.setUndecorated(b)); Core.graphics.setVSync(Core.settings.getBool("vsync")); if(Core.settings.getBool("fullscreen")){ Core.app.post(() -> Core.graphics.setFullscreenMode(Core.graphics.getDisplayMode())); } if(Core.settings.getBool("borderlesswindow")){ Core.app.post(() -> Core.graphics.setUndecorated(true)); } }else if(!ios){ graphics.checkPref("landscape", false, b -> { if(b){ platform.beginForceLandscape(); }else{ platform.endForceLandscape(); } }); if(Core.settings.getBool("landscape")){ platform.beginForceLandscape(); } } graphics.checkPref("effects", true); graphics.checkPref("destroyedblocks", true); graphics.checkPref("playerchat", true); graphics.checkPref("minimap", !mobile); graphics.checkPref("position", false); graphics.checkPref("fps", false); if(!mobile){ graphics.checkPref("blockselectkeys", true); } graphics.checkPref("indicators", true); graphics.checkPref("animatedwater", !mobile); if(Shaders.shield != null){ graphics.checkPref("animatedshields", !mobile); } graphics.checkPref("bloom", !mobile, val -> renderer.toggleBloom(val)); graphics.checkPref("pixelate", false, val -> { if(val){ Events.fire(Trigger.enablePixelation); } }); graphics.checkPref("linear", !mobile, b -> { for(Texture tex : Core.atlas.getTextures()){ TextureFilter filter = b ? TextureFilter.Linear : TextureFilter.Nearest; tex.setFilter(filter, filter); } }); if(Core.settings.getBool("linear")){ for(Texture tex : Core.atlas.getTextures()){ TextureFilter filter = TextureFilter.Linear; tex.setFilter(filter, filter); } } if(!mobile){ Core.settings.put("swapdiagonal", false); } } private void back(){ rebuildMenu(); prefs.clearChildren(); prefs.add(menu); } private void visible(int index){ prefs.clearChildren(); prefs.add(new Table[]{game, graphics, sound}[index]); } @Override public void addCloseButton(){ buttons.addImageTextButton("$back", Icon.leftOpen, () -> { if(prefs.getChildren().first() != menu){ back(); }else{ hide(); } }).size(230f, 64f); keyDown(key -> { if(key == KeyCode.ESCAPE || key == KeyCode.BACK){ if(prefs.getChildren().first() != menu){ back(); }else{ hide(); } } }); } }