diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 7272ca6a06..0cd0cb9cf6 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -288,6 +288,7 @@ save.corrupted = Save file corrupted or invalid! empty = on = On off = Off +save.search = Search Saved Games... save.autosave = Autosave: {0} save.map = Map: {0} save.wave = Wave {0} @@ -381,7 +382,11 @@ editor.newmap = New Map editor.center = Center editor.search = Search Maps... editor.filters = Filter Maps -editor.showAll = Show Default Maps +editor.filters.mode = Gamemodes: +editor.filters.type = Map Type: +editor.filters.search = Search In: +editor.filters.author = Author +editor.filters.description = Description workshop = Workshop waves.title = Waves waves.remove = Remove diff --git a/core/src/mindustry/ui/dialogs/LoadDialog.java b/core/src/mindustry/ui/dialogs/LoadDialog.java index 6e2e56e2d8..b6dfccde38 100644 --- a/core/src/mindustry/ui/dialogs/LoadDialog.java +++ b/core/src/mindustry/ui/dialogs/LoadDialog.java @@ -8,7 +8,9 @@ import arc.scene.ui.*; import arc.scene.ui.layout.*; import arc.struct.*; import arc.util.*; +import mindustry.*; import mindustry.core.GameState.*; +import mindustry.game.*; import mindustry.game.Saves.*; import mindustry.gen.*; import mindustry.io.*; @@ -20,8 +22,12 @@ import java.io.*; import static mindustry.Vars.*; public class LoadDialog extends BaseDialog{ - ScrollPane pane; Table slots; + String searchString; + Gamemode filteredMode; + TextField searchField; + ScrollPane pane; + BaseDialog dialog; public LoadDialog(){ this("@loadgame"); @@ -43,9 +49,38 @@ public class LoadDialog extends BaseDialog{ slots = new Table(); pane = new ScrollPane(slots); + + rebuild(); + + Table search = new Table(); + search.image(Icon.zoom); + searchField = search.field("", t -> { + searchString = t.length() > 0 ? t.toLowerCase() : null; + rebuild(); + }).maxTextLength(50).growX().get(); + searchField.setMessageText("@save.search"); + for(Gamemode mode : Gamemode.all){ + TextureRegionDrawable icon = Vars.ui.getIcon("mode" + Strings.capitalize(mode.name())); + boolean sandbox = mode == Gamemode.sandbox; + if(Core.atlas.isFound(icon.getRegion()) || sandbox){ + search.button(sandbox ? Icon.terrain : icon, Styles.emptytogglei, () -> { + filteredMode = filteredMode == mode ? null : mode; + rebuild(); + }).size(60f).checked(b -> filteredMode == mode).tooltip("@mode." + mode.name() + ".name"); + } + } + pane.setFadeScrollBars(false); pane.setScrollingDisabled(true, false); + cont.add(search).growX(); + cont.row(); + cont.add(pane).growY(); + } + + public void rebuild(){ + + slots.clear(); slots.marginRight(24).marginLeft(20f); Time.runTask(2f, () -> Core.scene.setScrollFocus(pane)); @@ -58,7 +93,11 @@ public class LoadDialog extends BaseDialog{ boolean any = false; for(SaveSlot slot : array){ - if(slot.isHidden()) continue; + if(slot.isHidden() + || (searchString != null && !Strings.stripColors(slot.getName()).toLowerCase().contains(searchString)) + || (filteredMode != null && filteredMode != slot.mode())){ + continue; + } any = true; @@ -82,14 +121,14 @@ public class LoadDialog extends BaseDialog{ t.button(Icon.trash, Styles.emptyi, () -> { ui.showConfirm("@confirm", "@save.delete.confirm", () -> { slot.delete(); - setup(); + rebuild(); }); }).right(); t.button(Icon.pencil, Styles.emptyi, () -> { ui.showTextInput("@save.rename", "@save.rename.text", slot.getName(), text -> { slot.setName(text); - setup(); + rebuild(); }); }).right(); @@ -141,10 +180,8 @@ public class LoadDialog extends BaseDialog{ } if(!any){ - slots.button("@save.none", () -> {}).disabled(true).fillX().margin(20f).minWidth(340f).height(80f).pad(4f); + slots.add("@save.none"); } - - cont.add(pane); } public void addSetup(){ @@ -154,7 +191,7 @@ public class LoadDialog extends BaseDialog{ if(SaveIO.isSaveValid(file)){ try{ control.saves.importSave(file); - setup(); + rebuild(); }catch(IOException e){ e.printStackTrace(); ui.showException("@save.import.fail", e); @@ -193,4 +230,15 @@ public class LoadDialog extends BaseDialog{ } }); } + + @Override + public Dialog show(){ + super.show(); + + if(Core.app.isDesktop() && searchField != null){ + Core.scene.setKeyboardFocus(searchField); + } + + return this; + } } diff --git a/core/src/mindustry/ui/dialogs/MapsDialog.java b/core/src/mindustry/ui/dialogs/MapsDialog.java index af46fcba42..5b2aff38d3 100644 --- a/core/src/mindustry/ui/dialogs/MapsDialog.java +++ b/core/src/mindustry/ui/dialogs/MapsDialog.java @@ -25,7 +25,10 @@ public class MapsDialog extends BaseDialog{ private Table mapTable = new Table(); private TextField searchField; - private boolean showAll = Core.settings.getBool("editorShowAllMaps", true); + private boolean showBuiltIn = Core.settings.getBool("editorshowbuiltinmaps", true); + private boolean showCustom = Core.settings.getBool("editorshowcustommaps", true); + private boolean searchAuthor = Core.settings.getBool("editorsearchauthor", false); + private boolean searchDescription = Core.settings.getBool("editorsearchdescription", false); public MapsDialog(){ super("@maps"); @@ -87,7 +90,7 @@ public class MapsDialog extends BaseDialog{ String name = map.tags.get("name", () -> { String result = "unknown"; int number = 0; - while(maps.byName(result + number++) != null); + while(maps.byName(result + number++) != null) ; return result + number; }); @@ -153,35 +156,43 @@ public class MapsDialog extends BaseDialog{ int i = 0; - Seq mapList = showAll ? Vars.maps.all() : Vars.maps.customMaps(); - for(Map map : mapList){ + Seq mapList = showCustom ? + showBuiltIn ? maps.all() : maps.customMaps() : + showBuiltIn ? maps.defaultMaps() : null; - boolean invalid = false; - for(Gamemode mode : modes){ - invalid |= !mode.valid(map); + if(mapList != null){ + for(Map map : mapList){ + + boolean invalid = false; + for(Gamemode mode : modes){ + invalid |= !mode.valid(map); + } + if(invalid || (searchString != null + && !Strings.stripColors(map.name()).toLowerCase().contains(searchString) + && (!searchAuthor || !Strings.stripColors(map.author()).toLowerCase().contains(searchString)) + && (!searchDescription || !Strings.stripColors(map.description()).toLowerCase().contains(searchString)))){ + continue; + } + + noMapsShown = false; + + if(i % maxwidth == 0){ + mapTable.row(); + } + + TextButton button = mapTable.button("", Styles.cleart, () -> showMapInfo(map)).width(mapsize).pad(8).get(); + button.clearChildren(); + button.margin(9); + button.add(map.name()).width(mapsize - 18f).center().get().setEllipsis(true); + button.row(); + button.image().growX().pad(4).color(Pal.gray); + button.row(); + button.stack(new Image(map.safeTexture()).setScaling(Scaling.fit), new BorderImage(map.safeTexture()).setScaling(Scaling.fit)).size(mapsize - 20f); + button.row(); + button.add(map.custom ? "@custom" : map.workshop ? "@workshop" : map.mod != null ? "[lightgray]" + map.mod.meta.displayName() : "@builtin").color(Color.gray).padTop(3); + + i++; } - if(invalid || (searchString != null && !Strings.stripColors(map.name()).toLowerCase().contains(searchString))){ - continue; - } - - noMapsShown = false; - - if(i % maxwidth == 0){ - mapTable.row(); - } - - TextButton button = mapTable.button("", Styles.cleart, () -> showMapInfo(map)).width(mapsize).pad(8).get(); - button.clearChildren(); - button.margin(9); - button.add(map.name()).width(mapsize - 18f).center().get().setEllipsis(true); - button.row(); - button.image().growX().pad(4).color(Pal.gray); - button.row(); - button.stack(new Image(map.safeTexture()).setScaling(Scaling.fit), new BorderImage(map.safeTexture()).setScaling(Scaling.fit)).size(mapsize - 20f); - button.row(); - button.add(map.custom ? "@custom" : map.workshop ? "@workshop" : map.mod != null ? "[lightgray]" + map.mod.meta.displayName() : "@builtin").color(Color.gray).padTop(3); - - i++; } if(noMapsShown){ @@ -192,30 +203,57 @@ public class MapsDialog extends BaseDialog{ void showMapFilters(){ dialog = new BaseDialog("@editor.filters"); dialog.addCloseButton(); - dialog.setFillParent(false); - dialog.cont.table(Tex.button, t -> { - int i = 0; - for(Gamemode mode : Gamemode.all){ - TextureRegionDrawable icon = Vars.ui.getIcon("mode" + Strings.capitalize(mode.name())); - if(Core.atlas.isFound(icon.getRegion())){ - t.button(mode.name(), icon, Styles.clearTogglet, () -> { - if(modes.contains(mode)){ - modes.remove(mode); - }else{ - modes.add(mode); - } - rebuildMaps(); - }).size(150f, 60f).marginLeft(6f).checked(modes.contains(mode)); - if(++i % 3 == 0) t.row(); + dialog.cont.table(menu -> { + menu.add("@editor.filters.mode").width(150f).left(); + menu.table(t -> { + for(Gamemode mode : Gamemode.all){ + TextureRegionDrawable icon = Vars.ui.getIcon("mode" + Strings.capitalize(mode.name())); + if(Core.atlas.isFound(icon.getRegion())){ + t.button(icon, Styles.emptytogglei, () -> { + if(modes.contains(mode)){ + modes.remove(mode); + }else{ + modes.add(mode); + } + rebuildMaps(); + }).size(60f).checked(modes.contains(mode)).tooltip("@mode." + mode.name() + ".name"); + } } - } - t.row(); - t.button("@editor.showAll", Styles.clearTogglet, () -> { - showAll = !showAll; - Core.settings.put("editorShowAllMaps", showAll); - Core.settings.forceSave(); - rebuildMaps(); - }).checked(b -> showAll).colspan(3).growX().height(40f); + }).padBottom(10f); + menu.row(); + + menu.add("@editor.filters.type").width(150f).left(); + menu.table(Tex.button, t -> { + t.button("@custom", Styles.clearTogglet, () -> { + showCustom = !showCustom; + Core.settings.put("editorshowcustommaps", showCustom); + Core.settings.forceSave(); + rebuildMaps(); + }).size(150f, 60f).checked(showCustom); + t.button("@builtin", Styles.clearTogglet, () -> { + showBuiltIn = !showBuiltIn; + Core.settings.put("editorshowbuiltinmaps", showBuiltIn); + Core.settings.forceSave(); + rebuildMaps(); + }).size(150f, 60f).checked(showBuiltIn); + }).padBottom(10f); + menu.row(); + + menu.add("@editor.filters.search").width(150f).left(); + menu.table(Tex.button, t -> { + t.button("@editor.filters.author", Styles.clearTogglet, () -> { + searchAuthor = !searchAuthor; + Core.settings.put("editorsearchauthor", searchAuthor); + Core.settings.forceSave(); + rebuildMaps(); + }).size(150f, 60f).checked(searchAuthor); + t.button("@editor.filters.description", Styles.clearTogglet, () -> { + searchDescription = !searchDescription; + Core.settings.put("editorsearchdescription", searchDescription); + Core.settings.forceSave(); + rebuildMaps(); + }).size(150f, 60f).checked(searchDescription); + }); }); dialog.show();