From 23f1d24c45d4311c44197b1c87387891d0653a44 Mon Sep 17 00:00:00 2001 From: JniTrRny <85090668+JniTrRny@users.noreply.github.com> Date: Sun, 7 May 2023 21:42:45 +0700 Subject: [PATCH] Search bar for wave UI (#8501) * wave search + other editor things * everything but wave search --- core/assets/bundles/bundle.properties | 2 + .../src/mindustry/editor/MapEditorDialog.java | 6 +- core/src/mindustry/editor/MapLoadDialog.java | 13 +- core/src/mindustry/editor/WaveInfoDialog.java | 188 +++++++++++------- core/src/mindustry/game/SpawnGroup.java | 8 +- .../mindustry/maps/filters/FilterOption.java | 3 +- .../mindustry/world/blocks/ItemSelection.java | 10 +- 7 files changed, 138 insertions(+), 92 deletions(-) diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index e4111913e4..8b0088943c 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -462,6 +462,8 @@ waves.sort.reverse = Reverse Sort waves.sort.begin = Begin waves.sort.health = Health waves.sort.type = Type +waves.search = Search waves... +waves.filter.unit = Unit Filter waves.units.hide = Hide All waves.units.show = Show All diff --git a/core/src/mindustry/editor/MapEditorDialog.java b/core/src/mindustry/editor/MapEditorDialog.java index d727c950d7..1d30d18d82 100644 --- a/core/src/mindustry/editor/MapEditorDialog.java +++ b/core/src/mindustry/editor/MapEditorDialog.java @@ -752,9 +752,9 @@ public class MapEditorDialog extends Dialog implements Disposable{ cont.table(search -> { search.image(Icon.zoom).padRight(8); - search.field("", this::rebuildBlockSelection) + search.field("", this::rebuildBlockSelection).growX() .name("editor/search").maxTextLength(maxNameLength).get().setMessageText("@players.search"); - }).pad(-2); + }).growX().pad(-2).padLeft(6f); cont.row(); cont.table(Tex.underline, extra -> extra.labelWrap(() -> editor.drawBlock.localizedName).width(200f).center()).growX(); cont.row(); @@ -803,7 +803,7 @@ public class MapEditorDialog extends Dialog implements Disposable{ } if(i == 0){ - blockSelection.add("@none").color(Color.lightGray).padLeft(80f).padTop(10f); + blockSelection.add("@none.found").color(Color.lightGray).padLeft(54f).padTop(10f); } } } diff --git a/core/src/mindustry/editor/MapLoadDialog.java b/core/src/mindustry/editor/MapLoadDialog.java index 4ed63a1a7f..1217c87020 100644 --- a/core/src/mindustry/editor/MapLoadDialog.java +++ b/core/src/mindustry/editor/MapLoadDialog.java @@ -30,6 +30,7 @@ public class MapLoadDialog extends BaseDialog{ buttons.defaults().size(200f, 50f); buttons.button("@cancel", this::hide); buttons.add(button); + addCloseListener(); } public void rebuild(){ @@ -48,13 +49,13 @@ public class MapLoadDialog extends BaseDialog{ table.defaults().size(200f, 90f).pad(4f); table.margin(10f); - ScrollPane pane = new ScrollPane(table, Styles.horizontalPane); + ScrollPane pane = new ScrollPane(table); pane.setFadeScrollBars(false); for(Map map : maps.all()){ - TextButton button = new TextButton(map.name(), Styles.togglet); - button.add(new BorderImage(map.safeTexture(), 2f).setScaling(Scaling.fit)).size(16 * 4f); + TextButton button = new TextButton(map.name(), Styles.flatTogglet); + button.add(new BorderImage(map.safeTexture(), 2f).setScaling(Scaling.fit)).padLeft(5f).size(16 * 4f); button.getCells().reverse(); button.clicked(() -> selected = map); button.getLabelCell().grow().left().padLeft(5f); @@ -63,14 +64,12 @@ public class MapLoadDialog extends BaseDialog{ if(++i % maxcol == 0) table.row(); } - if(maps.all().size == 0){ + if(maps.all().isEmpty()){ table.add("@maps.none").center(); - }else{ - cont.add("@editor.loadmap"); } cont.row(); - cont.add(pane); + cont.add(pane).growX(); } } diff --git a/core/src/mindustry/editor/WaveInfoDialog.java b/core/src/mindustry/editor/WaveInfoDialog.java index cfbdb59f3c..66a29cd487 100644 --- a/core/src/mindustry/editor/WaveInfoDialog.java +++ b/core/src/mindustry/editor/WaveInfoDialog.java @@ -1,7 +1,9 @@ package mindustry.editor; import arc.*; +import arc.func.*; import arc.graphics.*; +import arc.input.*; import arc.math.*; import arc.math.geom.*; import arc.scene.event.*; @@ -21,19 +23,18 @@ import mindustry.type.*; import mindustry.ui.*; import mindustry.ui.dialogs.*; -import java.util.*; - import static mindustry.Vars.*; import static mindustry.game.SpawnGroup.*; public class WaveInfoDialog extends BaseDialog{ - private int displayed = 20; + private int start = 0, displayed = 20; Seq groups = new Seq<>(); - private SpawnGroup expandedGroup; + private @Nullable SpawnGroup expandedGroup; private Table table; - private int start = 0; + private int search = -1; private UnitType lastType = UnitTypes.dagger; + private @Nullable UnitType filterType; private Sort sort = Sort.begin; private boolean reverseSort = false; private float updateTimer, updatePeriod = 1f; @@ -49,45 +50,22 @@ public class WaveInfoDialog extends BaseDialog{ }); hidden(() -> state.rules.spawns = groups); - addCloseListener(); - onResize(this::setup); - buttons.button(Icon.filter, () -> { - BaseDialog dialog = new BaseDialog("@waves.sort"); - dialog.setFillParent(false); - dialog.cont.table(Tex.button, t -> { - for(Sort s : Sort.all){ - t.button("@waves.sort." + s, Styles.flatTogglet, () -> { - sort = s; - dialog.hide(); - buildGroups(); - }).size(150f, 60f).checked(s == sort); - } - }).row(); - dialog.cont.check("@waves.sort.reverse", b -> { - reverseSort = b; - buildGroups(); - }).padTop(4).checked(reverseSort).padBottom(8f); - dialog.addCloseButton(); - dialog.show(); - buildGroups(); - }).size(60f, 64f); - addCloseButton(); - buttons.button("@waves.edit", Icon.pencil, () -> { + buttons.button("@waves.edit", Icon.edit, () -> { BaseDialog dialog = new BaseDialog("@waves.edit"); dialog.addCloseButton(); dialog.setFillParent(false); dialog.cont.table(Tex.button, t -> { - var style = Styles.flatt; - t.defaults().size(210f, 58f); + var style = Styles.cleart; + t.defaults().size(280f, 64f).pad(2f); t.button("@waves.copy", Icon.copy, style, () -> { ui.showInfoFade("@waves.copied"); Core.app.setClipboardText(maps.writeWaves(groups)); dialog.hide(); - }).disabled(b -> groups == null).marginLeft(12f).row(); + }).disabled(b -> groups == null || groups.isEmpty()).marginLeft(12f).row(); t.button("@waves.load", Icon.download, style, () -> { try{ @@ -98,16 +76,16 @@ public class WaveInfoDialog extends BaseDialog{ ui.showErrorMessage("@waves.invalid"); } dialog.hide(); - }).marginLeft(12f).disabled(b -> Core.app.getClipboardText() == null || Core.app.getClipboardText().isEmpty()).row(); + }).disabled(Core.app.getClipboardText() == null || !Core.app.getClipboardText().startsWith("[")).marginLeft(12f).row(); - t.button("@settings.reset", Icon.upload, style, () -> ui.showConfirm("@confirm", "@settings.clear.confirm", () -> { - groups = JsonIO.copy(waves.get()); + t.button("@clear", Icon.none, style, () -> ui.showConfirm("@confirm", "@settings.clear.confirm", () -> { + groups.clear(); buildGroups(); dialog.hide(); })).marginLeft(12f).row(); - t.button("@clear", Icon.cancel, style, () -> ui.showConfirm("@confirm", "@settings.clear.confirm", () -> { - groups.clear(); + t.button("@settings.reset", Icon.refresh, style, () -> ui.showConfirm("@confirm", "@settings.clear.confirm", () -> { + groups = JsonIO.copy(waves.get()); buildGroups(); dialog.hide(); })).marginLeft(12f); @@ -144,7 +122,7 @@ public class WaveInfoDialog extends BaseDialog{ buttons.button(Core.bundle.get("waves.random"), Icon.refresh, () -> { groups.clear(); groups = Waves.generate(1f / 10f); - updateWaves(); + buildGroups(); }).width(200f); } } @@ -171,19 +149,53 @@ public class WaveInfoDialog extends BaseDialog{ void setup(){ groups = JsonIO.copy(state.rules.spawns.isEmpty() ? waves.get() : state.rules.spawns); + if(groups == null) groups = new Seq<>(); cont.clear(); cont.stack(new Table(Tex.clear, main -> { - main.pane(t -> table = t).growX().growY().padRight(8f).scrollX(false); - main.row(); - main.button("@add", () -> { - if(groups == null) groups = new Seq<>(); - SpawnGroup newGroup = new SpawnGroup(lastType); - groups.add(newGroup); - expandedGroup = newGroup; - showUpdate(newGroup); - buildGroups(); - }).growX().height(70f); + main.table(s -> { + s.image(Icon.zoom).padRight(8); + s.field(search < 0 ? "" : (search + 1) + "", TextFieldFilter.digitsOnly, text -> { + search = groups.any() ? Strings.parseInt(text, 0) - 1 : -1; + start = Math.max(search - (displayed / 2) - (displayed % 2), 0); + buildGroups(); + }).growX().maxTextLength(8).get().setMessageText("@waves.search"); + s.button(Icon.units, Styles.emptyi, () -> showUnits(type -> filterType = type, true)).size(46f).tooltip("@waves.filter.unit") + .update(b -> b.getStyle().imageUp = filterType != null ? new TextureRegionDrawable(filterType.uiIcon) : Icon.filter); + }).growX().pad(6f).row(); + + main.pane(t -> table = t).grow().padRight(8f).scrollX(false).row(); + + main.table(t -> { + t.button("@add", () -> { + SpawnGroup newGroup = new SpawnGroup(lastType); + groups.add(newGroup); + expandedGroup = newGroup; + showUnits(type -> newGroup.type = lastType = type, false); + buildGroups(); + }).growX().height(70f); + + t.button(Icon.filter, () -> { + BaseDialog dialog = new BaseDialog("@waves.sort"); + dialog.setFillParent(false); + dialog.cont.table(Tex.button, f -> { + for(Sort s : Sort.all){ + f.button("@waves.sort." + s, Styles.flatTogglet, () -> { + sort = s; + dialog.hide(); + buildGroups(); + }).size(150f, 60f).checked(s == sort); + } + }).row(); + dialog.cont.check("@waves.sort.reverse", b -> { + reverseSort = b; + buildGroups(); + }).padTop(4).checked(reverseSort).padBottom(8f); + dialog.addCloseButton(); + dialog.show(); + }).size(64f, 70f).padLeft(6f); + }).growX(); + }), new Label("@waves.none"){{ visible(() -> groups.isEmpty()); this.touchable = Touchable.disabled; @@ -202,10 +214,13 @@ public class WaveInfoDialog extends BaseDialog{ table.margin(10f); if(groups != null){ - groups.sort(sort.sort); + groups.sort(Structs.comps(Structs.comparingFloat(sort.sort), Structs.comparingFloat(sort.secondary))); if(reverseSort) groups.reverse(); for(SpawnGroup group : groups){ + if(group.effect == StatusEffects.none) group.effect = null; + if((search >= 0 && group.getSpawned(search) <= 0) || (filterType != null && group.type != filterType)) continue; + table.table(Tex.button, t -> { t.margin(0).defaults().pad(3).padLeft(5f).growX().left(); t.button(b -> { @@ -218,24 +233,31 @@ public class WaveInfoDialog extends BaseDialog{ b.label(() -> (group.begin + 1) + "").color(Color.lightGray).minWidth(45f).labelAlign(Align.left).left(); b.button(Icon.copySmall, Styles.emptyi, () -> { - SpawnGroup newGroup = group.copy(); - expandedGroup = newGroup; - groups.add(newGroup); + SpawnGroup copy = group.copy(); + expandedGroup = copy; + groups.insert(groups.indexOf(group) + 1, copy); buildGroups(); - }).pad(-6).size(46f); + }).pad(-6).size(46f).tooltip("@editor.copy"); - b.button(group.effect != null && group.effect != StatusEffects.none ? + b.button(group.effect != null ? new TextureRegionDrawable(group.effect.uiIcon) : Icon.logicSmall, - Styles.emptyi, () -> showEffect(group)).pad(-6).size(46f); + Styles.emptyi, () -> showEffects(group)).pad(-6).size(46f).scaling(Scaling.fit).tooltip(group.effect != null ? group.effect.localizedName : "@none"); - b.button(Icon.unitsSmall, Styles.emptyi, () -> showUpdate(group)).pad(-6).size(46f); + b.button(Icon.unitsSmall, Styles.emptyi, () -> showUnits(type -> group.type = lastType = type, false)).pad(-6).size(46f).tooltip("@stat.unittype"); b.button(Icon.cancel, Styles.emptyi, () -> { groups.remove(group); + if(expandedGroup == group) expandedGroup = null; table.getCell(t).pad(0f); t.remove(); buildGroups(); - }).pad(-6).size(46f).padRight(-12f); + }).pad(-6).size(46f).padRight(-12f).tooltip("@waves.remove"); + b.clicked(KeyCode.mouseMiddle, () -> { + SpawnGroup copy = group.copy(); + groups.insert(groups.indexOf(group) + 1, copy); + expandedGroup = copy; + buildGroups(); + }); }, () -> { expandedGroup = expandedGroup == group ? null : group; buildGroups(); @@ -369,7 +391,7 @@ public class WaveInfoDialog extends BaseDialog{ dialog.hide(); }).size(110f, 45f).checked(-1 == group.spawn); } - }); + }).grow(); dialog.setFillParent(false); dialog.addCloseButton(); dialog.show(); @@ -381,6 +403,10 @@ public class WaveInfoDialog extends BaseDialog{ table.row(); } + + if(table.getChildren().isEmpty() && groups.any()){ + table.add("@none.found"); + } }else{ table.add("@editor.default"); } @@ -388,11 +414,23 @@ public class WaveInfoDialog extends BaseDialog{ updateWaves(); } - void showUpdate(SpawnGroup group){ + void showUnits(Cons cons, boolean reset){ BaseDialog dialog = new BaseDialog(""); dialog.setFillParent(true); dialog.cont.pane(p -> { - int i = 0; + p.defaults().pad(2).fillX(); + if(reset){ + p.button(t -> { + t.left(); + t.image(Icon.none).size(8 * 4).scaling(Scaling.fit).padRight(2f); + t.add("@settings.resetKey"); + }, () -> { + cons.get(null); + dialog.hide(); + buildGroups(); + }).margin(12f); + } + int i = reset ? 1 : 0; for(UnitType type : content.units()){ if(type.isHidden()) continue; p.button(t -> { @@ -400,19 +438,18 @@ public class WaveInfoDialog extends BaseDialog{ t.image(type.uiIcon).size(8 * 4).scaling(Scaling.fit).padRight(2f); t.add(type.localizedName); }, () -> { - lastType = type; - group.type = type; + cons.get(type); dialog.hide(); buildGroups(); - }).pad(2).margin(12f).fillX(); + }).margin(12f); if(++i % 3 == 0) p.row(); } - }); + }).growX().scrollX(false); dialog.addCloseButton(); dialog.show(); } - void showEffect(SpawnGroup group){ + void showEffects(SpawnGroup group){ BaseDialog dialog = new BaseDialog(""); dialog.setFillParent(true); dialog.cont.pane(p -> { @@ -434,28 +471,33 @@ public class WaveInfoDialog extends BaseDialog{ t.add("@settings.resetKey"); } }, () -> { - group.effect = effect; + group.effect = effect != StatusEffects.none ? effect : null; dialog.hide(); buildGroups(); }).pad(2).margin(12f).fillX(); if(++i % 3 == 0) p.row(); } - }); + }).growX().scrollX(false); dialog.addCloseButton(); dialog.show(); } enum Sort{ - begin(Structs.comps(Structs.comparingFloat(g -> g.begin), Structs.comparingFloat(g -> g.type.id))), - health(Structs.comps(Structs.comparingFloat(g -> g.type.health), Structs.comparingFloat(g -> g.begin))), - type(Structs.comps(Structs.comparingFloat(g -> g.type.id), Structs.comparingFloat(g -> g.begin))); + begin(g -> g.begin, g -> g.type.id), + health(g -> g.type.health), + type(g -> g.type.id); static final Sort[] all = values(); - final Comparator sort; + final Floatf sort, secondary; - Sort(Comparator sort){ + Sort(Floatf sort){ + this(sort, g -> g.begin); + } + + Sort(Floatf sort, Floatf secondary){ this.sort = sort; + this.secondary = secondary; } } @@ -465,4 +507,4 @@ public class WaveInfoDialog extends BaseDialog{ graph.to = start + displayed; graph.rebuild(); } -} +} \ No newline at end of file diff --git a/core/src/mindustry/game/SpawnGroup.java b/core/src/mindustry/game/SpawnGroup.java index b4877e7917..d155c8bc60 100644 --- a/core/src/mindustry/game/SpawnGroup.java +++ b/core/src/mindustry/game/SpawnGroup.java @@ -118,7 +118,7 @@ public class SpawnGroup implements JsonSerializable, Cloneable{ if(unitAmount != 1) json.writeValue("amount", unitAmount); if(effect != null) json.writeValue("effect", effect.name); if(spawn != -1) json.writeValue("spawn", spawn); - if(payloads != null && payloads.size > 0) json.writeValue("payloads", payloads.map(u -> u.name).toArray(String.class)); + if(payloads != null && payloads.any()) json.writeValue("payloads", payloads.map(u -> u.name).toArray(String.class)); if(items != null && items.amount > 0) json.writeValue("items", items); } @@ -127,7 +127,7 @@ public class SpawnGroup implements JsonSerializable, Cloneable{ public void read(Json json, JsonValue data){ String tname = data.getString("type", "dagger"); - type = content.getByName(ContentType.unit, LegacyIO.unitMap.get(tname, tname)); + type = content.unit(LegacyIO.unitMap.get(tname, tname)); if(type == null) type = UnitTypes.dagger; begin = data.getInt("begin", 0); end = data.getInt("end", never); @@ -138,7 +138,7 @@ public class SpawnGroup implements JsonSerializable, Cloneable{ shieldScaling = data.getFloat("shieldScaling", 0); unitAmount = data.getInt("amount", 1); spawn = data.getInt("spawn", -1); - if(data.has("payloads")) payloads = Seq.with(json.readValue(String[].class, data.get("payloads"))).map(s -> content.getByName(ContentType.unit, s)); + if(data.has("payloads")) payloads = Seq.with(json.readValue(String[].class, data.get("payloads"))).map(s -> content.unit(s)); if(data.has("items")) items = json.readValue(ItemStack.class, data.get("items")); @@ -146,7 +146,7 @@ public class SpawnGroup implements JsonSerializable, Cloneable{ if(data.has("effect") && data.get("effect").isNumber() && data.getInt("effect", -1) == 8){ effect = StatusEffects.boss; }else{ - effect = content.getByName(ContentType.status, data.has("effect") && data.get("effect").isString() ? data.getString("effect", "none") : "none"); + effect = content.statusEffect(data.has("effect") && data.get("effect").isString() ? data.getString("effect", "none") : "none"); } } diff --git a/core/src/mindustry/maps/filters/FilterOption.java b/core/src/mindustry/maps/filters/FilterOption.java index 3082145494..da8921a195 100644 --- a/core/src/mindustry/maps/filters/FilterOption.java +++ b/core/src/mindustry/maps/filters/FilterOption.java @@ -108,6 +108,7 @@ public abstract class FilterOption{ .setRegion(supplier.get() == Blocks.air ? Icon.none.getRegion() : supplier.get().uiIcon)).size(iconSmall), () -> { BaseDialog dialog = new BaseDialog("@filter.option." + name); dialog.cont.pane(t -> { + t.margin(14f); int i = 0; for(Block block : Vars.content.blocks()){ if(!filter.get(block)) continue; @@ -120,7 +121,7 @@ public abstract class FilterOption{ if(++i % 10 == 0) t.row(); } dialog.setFillParent(i > 100); - }).padRight(8f).scrollX(false); + }).scrollX(false); dialog.addCloseButton(); diff --git a/core/src/mindustry/world/blocks/ItemSelection.java b/core/src/mindustry/world/blocks/ItemSelection.java index 1f833e6958..27172bc307 100644 --- a/core/src/mindustry/world/blocks/ItemSelection.java +++ b/core/src/mindustry/world/blocks/ItemSelection.java @@ -85,9 +85,11 @@ public class ItemSelection{ Table main = new Table().background(Styles.black6); if(rowCount > rows * 1.5f){ - search = main.field(null, text -> rebuild.run()).width(40 * columns).padBottom(4).left().growX().get(); - search.setMessageText("@players.search"); - main.row(); + main.table(s -> { + s.image(Icon.zoom).padLeft(4f); + search = s.field(null, text -> rebuild.run()).width(40 * columns).padBottom(4).left().growX().get(); + search.setMessageText("@players.search"); + }).row(); } ScrollPane pane = new ScrollPane(cont, Styles.smallPane); @@ -101,7 +103,7 @@ public class ItemSelection{ } pane.setOverscroll(false, false); - main.add(pane).maxHeight(40 * rows); + main.add(pane).growX().maxHeight(40 * rows); table.top().add(main); } } \ No newline at end of file