848 lines
28 KiB
Java
848 lines
28 KiB
Java
package mindustry.ui.dialogs;
|
|
|
|
import arc.*;
|
|
import arc.files.*;
|
|
import arc.func.*;
|
|
import arc.graphics.*;
|
|
import arc.graphics.Texture.*;
|
|
import arc.input.*;
|
|
import arc.scene.*;
|
|
import arc.scene.event.*;
|
|
import arc.scene.style.*;
|
|
import arc.scene.ui.*;
|
|
import arc.scene.ui.TextButton.*;
|
|
import arc.scene.ui.layout.*;
|
|
import arc.struct.*;
|
|
import arc.util.*;
|
|
import arc.util.io.*;
|
|
import mindustry.content.*;
|
|
import mindustry.content.TechTree.*;
|
|
import mindustry.core.*;
|
|
import mindustry.ctype.*;
|
|
import mindustry.game.EventType.*;
|
|
import mindustry.gen.*;
|
|
import mindustry.graphics.*;
|
|
import mindustry.input.*;
|
|
import mindustry.ui.*;
|
|
|
|
import java.io.*;
|
|
import java.util.zip.*;
|
|
|
|
import static arc.Core.*;
|
|
import static mindustry.Vars.*;
|
|
|
|
public class SettingsMenuDialog extends BaseDialog{
|
|
public SettingsTable graphics;
|
|
public SettingsTable game;
|
|
public SettingsTable sound;
|
|
public SettingsTable main;
|
|
|
|
private Table prefs;
|
|
private Table menu;
|
|
private BaseDialog dataDialog;
|
|
private Seq<SettingsCategory> categories = new Seq<>();
|
|
|
|
public SettingsMenuDialog(){
|
|
super(bundle.get("settings", "Settings"));
|
|
addCloseButton();
|
|
|
|
cont.add(main = new SettingsTable());
|
|
shouldPause = true;
|
|
|
|
shown(() -> {
|
|
back();
|
|
rebuildMenu();
|
|
});
|
|
|
|
onResize(() -> {
|
|
graphics.rebuild();
|
|
sound.rebuild();
|
|
game.rebuild();
|
|
updateScrollFocus();
|
|
});
|
|
|
|
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 BaseDialog("@settings.data");
|
|
dataDialog.addCloseButton();
|
|
|
|
dataDialog.cont.table(Tex.button, t -> {
|
|
t.defaults().size(280f, 60f).left();
|
|
TextButtonStyle style = Styles.flatt;
|
|
|
|
t.button("@settings.cleardata", Icon.trash, style, () -> ui.showConfirm("@confirm", "@settings.clearall.confirm", () -> {
|
|
ObjectMap<String, Object> map = new ObjectMap<>();
|
|
for(String value : Core.settings.keys()){
|
|
if(value.contains("usid") || value.contains("uuid")){
|
|
map.put(value, Core.settings.get(value, null));
|
|
}
|
|
}
|
|
Core.settings.clear();
|
|
Core.settings.putAll(map);
|
|
|
|
for(Fi file : dataDirectory.list()){
|
|
file.deleteDirectory();
|
|
}
|
|
|
|
Core.app.exit();
|
|
})).marginLeft(4);
|
|
|
|
t.row();
|
|
|
|
t.button("@settings.clearsaves", Icon.trash, style, () -> {
|
|
ui.showConfirm("@confirm", "@settings.clearsaves.confirm", () -> {
|
|
control.saves.deleteAll();
|
|
});
|
|
}).marginLeft(4);
|
|
|
|
t.row();
|
|
|
|
t.button("@settings.clearresearch", Icon.trash, style, () -> {
|
|
ui.showConfirm("@confirm", "@settings.clearresearch.confirm", () -> {
|
|
universe.clearLoadoutInfo();
|
|
for(TechNode node : TechTree.all){
|
|
node.reset();
|
|
}
|
|
content.each(c -> {
|
|
if(c instanceof UnlockableContent u){
|
|
u.clearUnlock();
|
|
}
|
|
});
|
|
settings.remove("unlocks");
|
|
});
|
|
}).marginLeft(4);
|
|
|
|
t.row();
|
|
|
|
t.button("@settings.clearcampaignsaves", Icon.trash, style, () -> {
|
|
ui.showConfirm("@confirm", "@settings.clearcampaignsaves.confirm", () -> {
|
|
for(var planet : content.planets()){
|
|
for(var sec : planet.sectors){
|
|
sec.clearInfo();
|
|
if(sec.save != null){
|
|
sec.save.delete();
|
|
sec.save = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
for(var slot : control.saves.getSaveSlots().copy()){
|
|
if(slot.isSector()){
|
|
slot.delete();
|
|
}
|
|
}
|
|
});
|
|
}).marginLeft(4);
|
|
|
|
t.row();
|
|
|
|
t.button("@data.export", Icon.upload, style, () -> {
|
|
if(ios){
|
|
Fi file = Core.files.local("mindustry-data-export.zip");
|
|
try{
|
|
exportData(file);
|
|
}catch(Exception e){
|
|
ui.showException(e);
|
|
}
|
|
platform.shareFile(file);
|
|
}else{
|
|
platform.showFileChooser(false, "zip", file -> {
|
|
try{
|
|
exportData(file);
|
|
ui.showInfo("@data.exported");
|
|
}catch(Exception e){
|
|
e.printStackTrace();
|
|
ui.showException(e);
|
|
}
|
|
});
|
|
}
|
|
}).marginLeft(4);
|
|
|
|
t.row();
|
|
|
|
t.button("@data.import", Icon.download, style, () -> ui.showConfirm("@confirm", "@data.import.confirm", () -> platform.showFileChooser(true, "zip", file -> {
|
|
try{
|
|
importData(file);
|
|
control.saves.resetSave();
|
|
state = new GameState();
|
|
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");
|
|
}
|
|
}
|
|
}))).marginLeft(4);
|
|
|
|
if(!mobile){
|
|
t.row();
|
|
t.button("@data.openfolder", Icon.folder, style, () -> Core.app.openFolder(Core.settings.getDataDirectory().absolutePath())).marginLeft(4);
|
|
}
|
|
|
|
t.row();
|
|
|
|
t.button("@crash.export", Icon.upload, style, () -> {
|
|
if(settings.getDataDirectory().child("crashes").list().length == 0 && !settings.getDataDirectory().child("last_log.txt").exists()){
|
|
ui.showInfo("@crash.none");
|
|
}else{
|
|
if(ios){
|
|
Fi logs = tmpDirectory.child("logs.txt");
|
|
logs.writeString(getLogs());
|
|
platform.shareFile(logs);
|
|
}else{
|
|
platform.showFileChooser(false, "txt", file -> {
|
|
try{
|
|
file.writeBytes(getLogs().getBytes(Strings.utf8));
|
|
app.post(() -> ui.showInfo("@crash.exported"));
|
|
}catch(Throwable e){
|
|
ui.showException(e);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}).marginLeft(4);
|
|
});
|
|
|
|
row();
|
|
pane(prefs).grow().top();
|
|
row();
|
|
add(buttons).fillX();
|
|
|
|
addSettings();
|
|
}
|
|
|
|
String getLogs(){
|
|
Fi log = settings.getDataDirectory().child("last_log.txt");
|
|
|
|
StringBuilder out = new StringBuilder();
|
|
for(Fi fi : settings.getDataDirectory().child("crashes").list()){
|
|
out.append(fi.name()).append("\n\n").append(fi.readString()).append("\n");
|
|
}
|
|
|
|
if(log.exists()){
|
|
out.append("\nlast log:\n").append(log.readString());
|
|
}
|
|
|
|
return out.toString();
|
|
}
|
|
|
|
/** Adds a custom settings category, with the icon being the specified region. */
|
|
public void addCategory(String name, @Nullable String region, Cons<SettingsTable> builder){
|
|
categories.add(new SettingsCategory(name, region == null ? null : new TextureRegionDrawable(atlas.find(region)), builder));
|
|
}
|
|
|
|
/** Adds a custom settings category, for use in mods. The specified consumer should add all relevant mod settings to the table. */
|
|
public void addCategory(String name, @Nullable Drawable icon, Cons<SettingsTable> builder){
|
|
categories.add(new SettingsCategory(name, icon, builder));
|
|
}
|
|
|
|
/** Adds a custom settings category, for use in mods. The specified consumer should add all relevant mod settings to the table. */
|
|
public void addCategory(String name, Cons<SettingsTable> builder){
|
|
addCategory(name, (Drawable)null, builder);
|
|
}
|
|
|
|
public Seq<SettingsCategory> getCategories(){
|
|
return categories;
|
|
}
|
|
|
|
void rebuildMenu(){
|
|
menu.clearChildren();
|
|
|
|
TextButtonStyle style = Styles.flatt;
|
|
|
|
float marg = 8f, isize = iconMed;
|
|
|
|
menu.defaults().size(300f, 60f);
|
|
menu.button("@settings.game", Icon.settings, style, isize, () -> visible(0)).marginLeft(marg).row();
|
|
menu.button("@settings.graphics", Icon.image, style, isize, () -> visible(1)).marginLeft(marg).row();
|
|
menu.button("@settings.sound", Icon.filters, style, isize, () -> visible(2)).marginLeft(marg).row();
|
|
menu.button("@settings.language", Icon.chat, style, isize, ui.language::show).marginLeft(marg).row();
|
|
if(!mobile || Core.settings.getBool("keyboard")){
|
|
menu.button("@settings.controls", Icon.move, style, isize, ui.controls::show).marginLeft(marg).row();
|
|
}
|
|
|
|
menu.button("@settings.data", Icon.save, style, isize, () -> dataDialog.show()).marginLeft(marg).row();
|
|
|
|
int i = 3;
|
|
for(var cat : categories){
|
|
int index = i;
|
|
if(cat.icon == null){
|
|
menu.button(cat.name, style, () -> visible(index)).marginLeft(marg).row();
|
|
}else{
|
|
menu.button(cat.name, cat.icon, style, isize, () -> visible(index)).with(b -> ((Image)b.getChildren().get(1)).setScaling(Scaling.fit)).marginLeft(marg).row();
|
|
}
|
|
i++;
|
|
}
|
|
}
|
|
|
|
void addSettings(){
|
|
sound.sliderPref("musicvol", 100, 0, 100, 1, i -> i + "%");
|
|
sound.sliderPref("sfxvol", 100, 0, 100, 1, i -> i + "%");
|
|
sound.sliderPref("ambientvol", 100, 0, 100, 1, i -> i + "%");
|
|
|
|
game.sliderPref("saveinterval", 60, 10, 5 * 120, 10, i -> Core.bundle.format("setting.seconds", i));
|
|
|
|
if(mobile){
|
|
game.checkPref("autotarget", true);
|
|
if(!ios){
|
|
game.checkPref("keyboard", false, val -> {
|
|
control.setInput(val ? new DesktopInput() : new MobileInput());
|
|
input.setUseKeyboard(val);
|
|
});
|
|
if(Core.settings.getBool("keyboard")){
|
|
control.setInput(new DesktopInput());
|
|
input.setUseKeyboard(true);
|
|
}
|
|
}else{
|
|
Core.settings.put("keyboard", false);
|
|
}
|
|
}
|
|
//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());
|
|
}
|
|
}*/
|
|
|
|
if(!mobile){
|
|
game.checkPref("crashreport", true);
|
|
}
|
|
|
|
game.checkPref("savecreate", true);
|
|
game.checkPref("blockreplace", true);
|
|
game.checkPref("conveyorpathfinding", true);
|
|
game.checkPref("hints", true);
|
|
game.checkPref("logichints", true);
|
|
|
|
if(!mobile){
|
|
game.checkPref("backgroundpause", true);
|
|
game.checkPref("buildautopause", false);
|
|
}
|
|
|
|
game.checkPref("doubletapmine", false);
|
|
game.checkPref("commandmodehold", true);
|
|
|
|
if(!ios){
|
|
game.checkPref("modcrashdisable", true);
|
|
}
|
|
|
|
if(steam){
|
|
game.sliderPref("playerlimit", 16, 2, 32, i -> {
|
|
platform.updateLobby();
|
|
return i + "";
|
|
});
|
|
|
|
if(!Version.modifier.contains("beta")){
|
|
game.checkPref("steampublichost", false, i -> {
|
|
platform.updateLobby();
|
|
});
|
|
}
|
|
}
|
|
|
|
if(!mobile){
|
|
game.checkPref("console", false);
|
|
}
|
|
|
|
int[] lastUiScale = {settings.getInt("uiscale", 100)};
|
|
|
|
graphics.sliderPref("uiscale", 100, 25, 300, 5, s -> {
|
|
//if the user changed their UI scale, but then put it back, don't consider it 'changed'
|
|
Core.settings.put("uiscalechanged", s != lastUiScale[0]);
|
|
return s + "%";
|
|
});
|
|
|
|
graphics.sliderPref("screenshake", 4, 0, 8, i -> (i / 4f) + "x");
|
|
|
|
graphics.sliderPref("bloomintensity", 6, 0, 16, i -> (int)(i/4f * 100f) + "%");
|
|
graphics.sliderPref("bloomblur", 2, 1, 16, i -> i + "x");
|
|
|
|
graphics.sliderPref("fpscap", 240, 10, 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", 100, 0, 100, 5, s -> s + "%");
|
|
|
|
if(!mobile){
|
|
graphics.checkPref("vsync", true, b -> Core.graphics.setVSync(b));
|
|
graphics.checkPref("fullscreen", false, b -> {
|
|
if(b && settings.getBool("borderlesswindow")){
|
|
Core.graphics.setWindowedMode(Core.graphics.getWidth(), Core.graphics.getHeight());
|
|
settings.put("borderlesswindow", false);
|
|
graphics.rebuild();
|
|
}
|
|
|
|
if(b){
|
|
Core.graphics.setFullscreen();
|
|
}else{
|
|
Core.graphics.setWindowedMode(Core.graphics.getWidth(), Core.graphics.getHeight());
|
|
}
|
|
});
|
|
|
|
graphics.checkPref("borderlesswindow", false, b -> {
|
|
if(b && settings.getBool("fullscreen")){
|
|
Core.graphics.setWindowedMode(Core.graphics.getWidth(), Core.graphics.getHeight());
|
|
settings.put("fullscreen", false);
|
|
graphics.rebuild();
|
|
}
|
|
Core.graphics.setBorderless(b);
|
|
});
|
|
|
|
Core.graphics.setVSync(Core.settings.getBool("vsync"));
|
|
|
|
if(Core.settings.getBool("fullscreen")){
|
|
Core.app.post(() -> Core.graphics.setFullscreen());
|
|
}
|
|
|
|
if(Core.settings.getBool("borderlesswindow")){
|
|
Core.app.post(() -> Core.graphics.setBorderless(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("atmosphere", !mobile);
|
|
graphics.checkPref("destroyedblocks", true);
|
|
graphics.checkPref("blockstatus", false);
|
|
graphics.checkPref("playerchat", true);
|
|
if(!mobile){
|
|
graphics.checkPref("coreitems", true);
|
|
}
|
|
graphics.checkPref("minimap", !mobile);
|
|
graphics.checkPref("smoothcamera", true);
|
|
graphics.checkPref("position", false);
|
|
if(!mobile){
|
|
graphics.checkPref("mouseposition", false);
|
|
}
|
|
graphics.checkPref("fps", false);
|
|
graphics.checkPref("playerindicators", true);
|
|
graphics.checkPref("indicators", true);
|
|
graphics.checkPref("showweather", true);
|
|
graphics.checkPref("animatedwater", true);
|
|
|
|
if(Shaders.shield != null){
|
|
graphics.checkPref("animatedshields", !mobile);
|
|
}
|
|
|
|
graphics.checkPref("bloom", true, val -> renderer.toggleBloom(val));
|
|
|
|
graphics.checkPref("pixelate", false, val -> {
|
|
if(val){
|
|
Events.fire(Trigger.enablePixelation);
|
|
}
|
|
});
|
|
|
|
//iOS (and possibly Android) devices do not support linear filtering well, so disable it
|
|
if(!ios){
|
|
graphics.checkPref("linear", !mobile, b -> {
|
|
for(Texture tex : Core.atlas.getTextures()){
|
|
TextureFilter filter = b ? TextureFilter.linear : TextureFilter.nearest;
|
|
tex.setFilter(filter, filter);
|
|
}
|
|
});
|
|
}else{
|
|
settings.put("linear", false);
|
|
}
|
|
|
|
if(Core.settings.getBool("linear")){
|
|
for(Texture tex : Core.atlas.getTextures()){
|
|
TextureFilter filter = TextureFilter.linear;
|
|
tex.setFilter(filter, filter);
|
|
}
|
|
}
|
|
|
|
graphics.checkPref("skipcoreanimation", false);
|
|
graphics.checkPref("hidedisplays", false);
|
|
|
|
if(OS.isMac){
|
|
graphics.checkPref("macnotch", false);
|
|
}
|
|
|
|
if(!mobile){
|
|
Core.settings.put("swapdiagonal", false);
|
|
}
|
|
}
|
|
|
|
public void exportData(Fi file) throws IOException{
|
|
Seq<Fi> files = new Seq<>();
|
|
files.add(Core.settings.getSettingsFile());
|
|
files.addAll(customMapDirectory.list());
|
|
files.addAll(saveDirectory.list());
|
|
files.addAll(modDirectory.list());
|
|
files.addAll(schematicDirectory.list());
|
|
String base = Core.settings.getDataDirectory().path();
|
|
|
|
//add directories
|
|
for(Fi other : files.copy()){
|
|
Fi parent = other.parent();
|
|
while(!files.contains(parent) && !parent.equals(settings.getDataDirectory())){
|
|
files.add(parent);
|
|
}
|
|
}
|
|
|
|
try(OutputStream fos = file.write(false, 2048); ZipOutputStream zos = new ZipOutputStream(fos)){
|
|
for(Fi add : files){
|
|
String path = add.path().substring(base.length());
|
|
if(add.isDirectory()) path += "/";
|
|
//fix trailing / in path
|
|
path = path.startsWith("/") ? path.substring(1) : path;
|
|
zos.putNextEntry(new ZipEntry(path));
|
|
if(!add.isDirectory()){
|
|
try(var stream = add.read()){
|
|
Streams.copy(stream, zos);
|
|
}
|
|
}
|
|
zos.closeEntry();
|
|
}
|
|
}
|
|
}
|
|
|
|
public void importData(Fi file){
|
|
Fi dest = Core.files.local("zipdata.zip");
|
|
file.copyTo(dest);
|
|
Fi zipped = new ZipFi(dest);
|
|
|
|
Fi base = Core.settings.getDataDirectory();
|
|
if(!zipped.child("settings.bin").exists()){
|
|
throw new IllegalArgumentException("Not valid save data.");
|
|
}
|
|
|
|
//delete old saves so they don't interfere
|
|
saveDirectory.deleteDirectory();
|
|
|
|
//purge existing tmp data, keep everything else
|
|
tmpDirectory.deleteDirectory();
|
|
|
|
zipped.walk(f -> f.copyTo(base.child(f.path())));
|
|
dest.delete();
|
|
|
|
//clear old data
|
|
settings.clear();
|
|
//load data so it's saved on exit
|
|
settings.load();
|
|
}
|
|
|
|
private void back(){
|
|
rebuildMenu();
|
|
prefs.clearChildren();
|
|
prefs.add(menu);
|
|
}
|
|
|
|
private void visible(int index){
|
|
prefs.clearChildren();
|
|
|
|
Seq<Table> tables = new Seq<>();
|
|
tables.addAll(game, graphics, sound);
|
|
for(var custom : categories){
|
|
tables.add(custom.table);
|
|
}
|
|
|
|
prefs.add(tables.get(index));
|
|
}
|
|
|
|
@Override
|
|
public void addCloseButton(){
|
|
buttons.button("@back", Icon.left, () -> {
|
|
if(prefs.getChildren().first() != menu){
|
|
back();
|
|
}else{
|
|
hide();
|
|
}
|
|
}).size(210f, 64f);
|
|
|
|
keyDown(key -> {
|
|
if(key == KeyCode.escape || key == KeyCode.back){
|
|
if(prefs.getChildren().first() != menu){
|
|
back();
|
|
}else{
|
|
hide();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
public interface StringProcessor{
|
|
String get(int i);
|
|
}
|
|
|
|
public static class SettingsCategory{
|
|
public String name;
|
|
public @Nullable Drawable icon;
|
|
public Cons<SettingsTable> builder;
|
|
public SettingsTable table;
|
|
|
|
public SettingsCategory(String name, Drawable icon, Cons<SettingsTable> builder){
|
|
this.name = name;
|
|
this.icon = icon;
|
|
this.builder = builder;
|
|
|
|
table = new SettingsTable();
|
|
builder.get(table);
|
|
}
|
|
}
|
|
|
|
public static class SettingsTable extends Table{
|
|
protected Seq<Setting> list = new Seq<>();
|
|
|
|
public SettingsTable(){
|
|
left();
|
|
}
|
|
|
|
public Seq<Setting> getSettings(){
|
|
return list;
|
|
}
|
|
|
|
public void pref(Setting setting){
|
|
list.add(setting);
|
|
rebuild();
|
|
}
|
|
|
|
public SliderSetting sliderPref(String name, int def, int min, int max, StringProcessor s){
|
|
return sliderPref(name, def, min, max, 1, s);
|
|
}
|
|
|
|
public SliderSetting sliderPref(String name, int def, int min, int max, int step, StringProcessor s){
|
|
SliderSetting res;
|
|
list.add(res = new SliderSetting(name, def, min, max, step, s));
|
|
settings.defaults(name, def);
|
|
rebuild();
|
|
return res;
|
|
}
|
|
|
|
public void checkPref(String name, boolean def){
|
|
list.add(new CheckSetting(name, def, null));
|
|
settings.defaults(name, def);
|
|
rebuild();
|
|
}
|
|
|
|
public void checkPref(String name, boolean def, Boolc changed){
|
|
list.add(new CheckSetting(name, def, changed));
|
|
settings.defaults(name, def);
|
|
rebuild();
|
|
}
|
|
|
|
public void textPref(String name, String def){
|
|
list.add(new TextSetting(name, def, null));
|
|
settings.defaults(name, def);
|
|
rebuild();
|
|
}
|
|
|
|
public void textPref(String name, String def, Cons<String> changed){
|
|
list.add(new TextSetting(name, def, changed));
|
|
settings.defaults(name, def);
|
|
rebuild();
|
|
}
|
|
|
|
public void areaTextPref(String name, String def){
|
|
list.add(new AreaTextSetting(name, def, null));
|
|
settings.defaults(name, def);
|
|
rebuild();
|
|
}
|
|
|
|
public void areaTextPref(String name, String def, Cons<String> changed){
|
|
list.add(new AreaTextSetting(name, def, changed));
|
|
settings.defaults(name, def);
|
|
rebuild();
|
|
}
|
|
|
|
public void rebuild(){
|
|
clearChildren();
|
|
|
|
for(Setting setting : list){
|
|
setting.add(this);
|
|
}
|
|
|
|
button(bundle.get("settings.reset", "Reset to Defaults"), () -> {
|
|
for(Setting setting : list){
|
|
if(setting.name == null || setting.title == null) continue;
|
|
settings.remove(setting.name);
|
|
}
|
|
rebuild();
|
|
}).margin(14).width(240f).pad(6);
|
|
}
|
|
|
|
public abstract static class Setting{
|
|
public String name;
|
|
public String title;
|
|
public @Nullable String description;
|
|
|
|
public Setting(String name){
|
|
this.name = name;
|
|
String winkey = "setting." + name + ".name.windows";
|
|
title = OS.isWindows && bundle.has(winkey) ? bundle.get(winkey) : bundle.get("setting." + name + ".name", name);
|
|
description = bundle.getOrNull("setting." + name + ".description");
|
|
}
|
|
|
|
public abstract void add(SettingsTable table);
|
|
|
|
public void addDesc(Element elem){
|
|
ui.addDescTooltip(elem, description);
|
|
}
|
|
}
|
|
|
|
public static class CheckSetting extends Setting{
|
|
boolean def;
|
|
Boolc changed;
|
|
|
|
public CheckSetting(String name, boolean def, Boolc changed){
|
|
super(name);
|
|
this.def = def;
|
|
this.changed = changed;
|
|
}
|
|
|
|
@Override
|
|
public void add(SettingsTable table){
|
|
CheckBox box = new CheckBox(title);
|
|
|
|
box.update(() -> box.setChecked(settings.getBool(name)));
|
|
|
|
box.changed(() -> {
|
|
settings.put(name, box.isChecked());
|
|
if(changed != null){
|
|
changed.get(box.isChecked());
|
|
}
|
|
});
|
|
|
|
box.left();
|
|
addDesc(table.add(box).left().padTop(3f).get());
|
|
table.row();
|
|
}
|
|
}
|
|
|
|
public static class SliderSetting extends Setting{
|
|
int def, min, max, step;
|
|
StringProcessor sp;
|
|
|
|
public SliderSetting(String name, int def, int min, int max, int step, StringProcessor s){
|
|
super(name);
|
|
this.def = def;
|
|
this.min = min;
|
|
this.max = max;
|
|
this.step = step;
|
|
this.sp = s;
|
|
}
|
|
|
|
@Override
|
|
public void add(SettingsTable table){
|
|
Slider slider = new Slider(min, max, step, false);
|
|
|
|
slider.setValue(settings.getInt(name));
|
|
|
|
Label value = new Label("", Styles.outlineLabel);
|
|
Table content = new Table();
|
|
content.add(title, Styles.outlineLabel).left().growX().wrap();
|
|
content.add(value).padLeft(10f).right();
|
|
content.margin(3f, 33f, 3f, 33f);
|
|
content.touchable = Touchable.disabled;
|
|
|
|
slider.changed(() -> {
|
|
settings.put(name, (int)slider.getValue());
|
|
value.setText(sp.get((int)slider.getValue()));
|
|
});
|
|
|
|
slider.change();
|
|
|
|
addDesc(table.stack(slider, content).width(Math.min(Core.graphics.getWidth() / 1.2f, 460f)).left().padTop(4f).get());
|
|
table.row();
|
|
}
|
|
}
|
|
|
|
public static class TextSetting extends Setting{
|
|
String def;
|
|
Cons<String> changed;
|
|
|
|
public TextSetting(String name, String def, Cons<String> changed){
|
|
super(name);
|
|
this.def = def;
|
|
this.changed = changed;
|
|
}
|
|
|
|
@Override
|
|
public void add(SettingsTable table){
|
|
TextField field = new TextField();
|
|
|
|
field.update(() -> field.setText(settings.getString(name)));
|
|
|
|
field.changed(() -> {
|
|
settings.put(name, field.getText());
|
|
if(changed != null){
|
|
changed.get(field.getText());
|
|
}
|
|
});
|
|
|
|
Table prefTable = table.table().left().padTop(3f).get();
|
|
prefTable.add(field);
|
|
prefTable.label(() -> title);
|
|
addDesc(prefTable);
|
|
table.row();
|
|
}
|
|
}
|
|
|
|
public static class AreaTextSetting extends TextSetting{
|
|
public AreaTextSetting(String name, String def, Cons<String> changed){
|
|
super(name, def, changed);
|
|
}
|
|
|
|
@Override
|
|
public void add(SettingsTable table){
|
|
TextArea area = new TextArea("");
|
|
area.setPrefRows(5);
|
|
|
|
area.update(() -> {
|
|
area.setText(settings.getString(name));
|
|
area.setWidth(table.getWidth());
|
|
});
|
|
|
|
area.changed(() -> {
|
|
settings.put(name, area.getText());
|
|
if(changed != null){
|
|
changed.get(area.getText());
|
|
}
|
|
});
|
|
|
|
addDesc(table.label(() -> title).left().padTop(3f).get());
|
|
table.row().add(area).left();
|
|
table.row();
|
|
}
|
|
}
|
|
}
|
|
}
|