From dcddabf8c16b6aac7bddb51b91b69360369632aa Mon Sep 17 00:00:00 2001 From: ApsZoldat <128713348+ApsZoldat@users.noreply.github.com> Date: Thu, 6 Feb 2025 21:32:02 +0300 Subject: [PATCH] Rules dialog changes (#9792) * Info buttons on mobile * Better banned content dialogs --------- Co-authored-by: Anuken --- core/assets/bundles/bundle.properties | 2 + .../mindustry/editor/BannedContentDialog.java | 210 ++++++++++++++++++ .../ui/dialogs/CustomRulesDialog.java | 117 +++------- 3 files changed, 239 insertions(+), 90 deletions(-) create mode 100644 core/src/mindustry/editor/BannedContentDialog.java diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index bf853461f0..2a336125db 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -729,8 +729,10 @@ loadout = Loadout resources = Resources resources.max = Max bannedblocks = Banned Blocks +unbannedblocks = Unbanned Blocks objectives = Objectives bannedunits = Banned Units +unbannedunits = Unbanned Units bannedunits.whitelist = Banned Units As Whitelist bannedblocks.whitelist = Banned Blocks As Whitelist addall = Add All diff --git a/core/src/mindustry/editor/BannedContentDialog.java b/core/src/mindustry/editor/BannedContentDialog.java new file mode 100644 index 0000000000..e401b3af73 --- /dev/null +++ b/core/src/mindustry/editor/BannedContentDialog.java @@ -0,0 +1,210 @@ +package mindustry.editor; + +import arc.*; +import arc.func.*; +import arc.graphics.*; +import arc.graphics.g2d.*; +import arc.scene.style.*; +import arc.scene.ui.*; +import arc.scene.ui.layout.*; +import arc.struct.*; +import arc.util.*; +import mindustry.ctype.*; +import mindustry.gen.*; +import mindustry.graphics.*; +import mindustry.type.*; +import mindustry.ui.*; +import mindustry.ui.dialogs.*; +import mindustry.world.*; + +import static mindustry.Vars.*; + +public class BannedContentDialog extends BaseDialog{ + private final ContentType type; + private Table selectedTable; + private Table deselectedTable; + private ObjectSet contentSet; + private final Boolf pred; + private String contentSearch; + private Category selectedCategory; + private Seq filteredContent; + + public BannedContentDialog(String title, ContentType type, Boolf pred){ + super(title); + this.type = type; + this.pred = pred; + contentSearch = ""; + + selectedTable = new Table(); + deselectedTable = new Table(); + + addCloseButton(); + + shown(this::build); + resized(this::build); + } + + public void show(ObjectSet contentSet){ + this.contentSet = contentSet; + show(); + } + + public void build(){ + cont.clear(); + + var cell = cont.table(t -> { + t.table(s -> { + s.label(() -> "@search").padRight(10); + var field = s.field(contentSearch, value -> { + contentSearch = value; + rebuildTables(); + }).get(); + s.button(Icon.cancel, Styles.emptyi, () -> { + contentSearch = ""; + field.setText(""); + rebuildTables(); + }).padLeft(10f).size(35f); + }); + if(type == ContentType.block){ + t.row(); + t.table(c -> { + c.marginTop(8f); + c.defaults().marginRight(4f); + for (Category category : Category.values()){ + c.button(ui.getIcon(category.name()), Styles.squareTogglei, () -> { + if(selectedCategory == category){ + selectedCategory = null; + }else{ + selectedCategory = category; + } + rebuildTables(); + }).size(45f).update(i -> i.setChecked(selectedCategory == category)).padLeft(4f); + } + c.add("").padRight(4f); + }).center(); + } + }); + cont.row(); + if(!Core.graphics.isPortrait()) cell.colspan(2); + + filteredContent = content.getBy(type).select(pred); + if(!contentSearch.isEmpty()) filteredContent.removeAll(content -> !content.localizedName.toLowerCase().contains(contentSearch.toLowerCase())); + + cont.table(table -> { + if(type == ContentType.block){ + table.add("@bannedblocks").color(Color.valueOf("f25555")).padBottom(-1).top().row(); + }else{ + table.add("@bannedunits").color(Color.valueOf("f25555")).padBottom(-1).top().row(); + } + + table.image().color(Color.valueOf("f25555")).height(3f).padBottom(5f).fillX().expandX().top().row(); + table.pane(table2 -> selectedTable = table2).fill().expand().row(); + table.button("@addall", Icon.add, () -> { + contentSet.addAll(filteredContent); + rebuildTables(); + }).disabled(button -> contentSet.toSeq().containsAll(filteredContent)).padTop(10f).bottom().fillX(); + }).fill().expandY().uniform(); + + if(Core.graphics.isPortrait()) cont.row(); + + var cell2 = cont.table(table -> { + if(type == ContentType.block){ + table.add("@unbannedblocks").color(Pal.accent).padBottom(-1).top().row(); + }else{ + table.add("@unbannedunits").color(Pal.accent).padBottom(-1).top().row(); + } + + table.image().color(Pal.accent).height(3f).padBottom(5f).fillX().top().row(); + table.pane(table2 -> deselectedTable = table2).fill().expand().row(); + table.button("@addall", Icon.add, () -> { + contentSet.removeAll(filteredContent); + rebuildTables(); + }).disabled(button -> { + Seq array = content.getBy(type); + array = array.copy(); + array.removeAll(contentSet.toSeq()); + return array.containsAll(filteredContent); + }).padTop(10f).bottom().fillX(); + }).fill().expandY().uniform(); + if(Core.graphics.isPortrait()){ + cell2.padTop(10f); + }else{ + cell2.padLeft(10f); + } + + rebuildTables(); + } + + private void rebuildTables(){ + filteredContent.clear(); + filteredContent = content.getBy(type); + filteredContent = filteredContent.select(pred); + + if(!contentSearch.isEmpty()) filteredContent.removeAll(content -> !content.localizedName.toLowerCase().contains(contentSearch.toLowerCase())); + if(type == ContentType.block){ + filteredContent.removeAll(content -> selectedCategory != null && ((Block)content).category != selectedCategory); + } + + rebuildTable(selectedTable, true); + rebuildTable(deselectedTable, false); + } + + private void rebuildTable(Table table, boolean isSelected){ + table.clear(); + + int cols; + if(Core.graphics.isPortrait()){ + cols = Math.max(4, (int)((Core.graphics.getWidth() / Scl.scl() - 100f) / 50f)); + }else{ + cols = Math.max(4, (int)((Core.graphics.getWidth() / Scl.scl() - 300f) / 50f / 2)); + } + + if((isSelected && contentSet.isEmpty()) || (!isSelected && contentSet.size == content.getBy(type).count(pred))){ + table.add("@empty").width(50f * cols).padBottom(5f).get().setAlignment(Align.center); + }else{ + Seq array; + if(!isSelected){ + array = content.getBy(type); + array = array.copy(); + array.removeAll(contentSet.toSeq()); + }else{ + array = contentSet.toSeq(); + } + array.sort(); + array.removeAll(content -> !filteredContent.contains(content)); + + if(array.isEmpty()){ + table.add("@empty").width(50f * cols).padBottom(5f).get().setAlignment(Align.center); + return; + } + int i = 0; + boolean requiresPad = true; + + for(T content : array){ + TextureRegion region = content.uiIcon; + + ImageButton button = new ImageButton(Tex.whiteui, Styles.squarei); + button.getStyle().imageUp = new TextureRegionDrawable(region); + button.resizeImage(8 * 4f); + if(isSelected) button.clicked(() -> { + contentSet.remove(content); + rebuildTables(); + }); + else button.clicked(() -> { + contentSet.add(content); + rebuildTables(); + }); + table.add(button).size(50f).tooltip(content.localizedName); + + if(++i % cols == 0){ + table.row(); + requiresPad = false; + } + } + + if(requiresPad){ + table.add("").padRight(50f * (cols - i)); + } + } + } +} diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java index 2eb0b17cde..83ef9ee840 100644 --- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java @@ -3,7 +3,6 @@ package mindustry.ui.dialogs; import arc.*; import arc.func.*; import arc.graphics.*; -import arc.scene.style.*; import arc.scene.ui.*; import arc.scene.ui.ImageButton.*; import arc.scene.ui.layout.*; @@ -12,6 +11,7 @@ import arc.util.*; import mindustry.*; import mindustry.content.*; import mindustry.ctype.*; +import mindustry.editor.BannedContentDialog; import mindustry.game.*; import mindustry.game.Rules.*; import mindustry.gen.*; @@ -30,7 +30,8 @@ public class CustomRulesDialog extends BaseDialog{ private Table main; private Prov resetter; private LoadoutDialog loadoutDialog; - + private BannedContentDialog bannedBlocks = new BannedContentDialog<>("@bannedblocks", ContentType.block, Block::canBeBuilt); + private BannedContentDialog bannedUnits = new BannedContentDialog<>("@bannedunits", ContentType.unit, u -> !u.isHidden()); public boolean showRuleEditRule; public Seq categories; public Table current; @@ -109,84 +110,6 @@ public class CustomRulesDialog extends BaseDialog{ requestScroll(); } - private void showBanned(String title, ContentType type, ObjectSet set, Boolf pred){ - BaseDialog bd = new BaseDialog(title); - bd.addCloseButton(); - - Runnable[] rebuild = {null}; - - rebuild[0] = () -> { - float previousScroll = bd.cont.getChildren().isEmpty() ? 0f : ((ScrollPane)bd.cont.getChildren().first()).getScrollY(); - bd.cont.clear(); - bd.cont.pane(t -> { - t.margin(10f); - - if(set.isEmpty()){ - t.add("@empty"); - } - - Seq array = set.toSeq(); - array.sort(); - - int cols = mobile && Core.graphics.isPortrait() ? 1 : mobile ? 2 : 3; - int i = 0; - - for(T con : array){ - t.table(Tex.underline, b -> { - b.left().margin(4f); - b.image(con.uiIcon).size(iconMed).padRight(3); - b.add(con.localizedName).color(Color.lightGray).padLeft(3).growX().left().wrap(); - - b.button(Icon.cancel, Styles.emptyi, () -> { - set.remove(con); - rebuild[0].run(); - }).size(70f).pad(-4f).padLeft(0f); - }).size(300f, 70f).padRight(5); - - if(++i % cols == 0){ - t.row(); - } - } - }).get().setScrollYForce(previousScroll); - bd.cont.row(); - bd.cont.button("@add", Icon.add, () -> { - BaseDialog dialog = new BaseDialog("@add"); - dialog.cont.pane(t -> { - t.left().margin(14f); - int[] i = {0}; - content.getBy(type).each(b -> !set.contains(b) && pred.get(b), b -> { - int cols = mobile && Core.graphics.isPortrait() ? 4 : 12; - t.button(new TextureRegionDrawable(b.uiIcon), Styles.flati, iconMed, () -> { - set.add(b); - rebuild[0].run(); - dialog.hide(); - }).size(60f).tooltip(b.localizedName); - - if(++i[0] % cols == 0){ - t.row(); - } - }); - }); - - dialog.addCloseButton(); - dialog.show(); - }).size(300f, 64f).disabled(b -> set.size == content.getBy(type).count(pred)); - }; - - bd.shown(rebuild[0]); - bd.buttons.button("@addall", Icon.add, () -> { - set.addAll(content.getBy(type).select(pred)); - rebuild[0].run(); - }).size(180, 64f); - - bd.buttons.button("@clear", Icon.trash, () -> { - set.clear(); - rebuild[0].run(); - }).size(180, 64f); - - bd.show(); - } - public void show(Rules rules, Prov resetter){ this.rules = rules; this.resetter = resetter; @@ -253,7 +176,7 @@ public class CustomRulesDialog extends BaseDialog{ } if(Core.bundle.get("bannedblocks").toLowerCase().contains(ruleSearch)){ - current.button("@bannedblocks", () -> showBanned("@bannedblocks", ContentType.block, rules.bannedBlocks, Block::canBeBuilt)).left().width(300f).row(); + current.button("@bannedblocks", () -> bannedBlocks.show(rules.bannedBlocks)).left().width(300f).row(); } check("@rules.hidebannedblocks", b -> rules.hideBannedBlocks = b, () -> rules.hideBannedBlocks); check("@bannedblocks.whitelist", b -> rules.blockWhitelist = b, () -> rules.blockWhitelist); @@ -271,7 +194,7 @@ public class CustomRulesDialog extends BaseDialog{ number("@rules.unithealthmultiplier", f -> rules.unitHealthMultiplier = f, () -> rules.unitHealthMultiplier); if(Core.bundle.get("bannedunits").toLowerCase().contains(ruleSearch)){ - current.button("@bannedunits", () -> showBanned("@bannedunits", ContentType.unit, rules.bannedUnits, u -> !u.isHidden())).left().width(300f).row(); + current.button("@bannedunits", () -> bannedUnits.show(rules.bannedUnits)).left().width(300f).row(); } check("@bannedunits.whitelist", b -> rules.unitWhitelist = b, () -> rules.unitWhitelist); @@ -458,7 +381,7 @@ public class CustomRulesDialog extends BaseDialog{ public void numberi(String text, Intc cons, Intp prov, Boolp condition, int min, int max){ if(!Core.bundle.get(text.substring(1)).toLowerCase().contains(ruleSearch)) return; - current.table(t -> { + var cell = current.table(t -> { t.left(); t.add(text).left().padRight(5) .update(a -> a.setColor(condition.get() ? Color.white : Color.gray)); @@ -466,12 +389,14 @@ public class CustomRulesDialog extends BaseDialog{ .update(a -> a.setDisabled(!condition.get())) .padRight(100f) .valid(f -> Strings.parseInt(f) >= min && Strings.parseInt(f) <= max).width(120f).left(); - }).padTop(0).row(); + }).padTop(0); + ruleInfo(cell, text); + current.row(); } public void number(String text, boolean integer, Floatc cons, Floatp prov, Boolp condition, float min, float max){ if(!Core.bundle.get(text.substring(1)).toLowerCase().contains(ruleSearch)) return; - current.table(t -> { + var cell = current.table(t -> { t.left(); t.add(text).left().padRight(5) .update(a -> a.setColor(condition.get() ? Color.white : Color.gray)); @@ -480,6 +405,7 @@ public class CustomRulesDialog extends BaseDialog{ .update(a -> a.setDisabled(!condition.get())) .valid(f -> Strings.canParsePositiveFloat(f) && Strings.parseFloat(f) >= min && Strings.parseFloat(f) <= max).width(120f).left(); }).padTop(0); + ruleInfo(cell, text); current.row(); } @@ -489,15 +415,26 @@ public class CustomRulesDialog extends BaseDialog{ public void check(String text, Boolc cons, Boolp prov, Boolp condition){ if(!Core.bundle.get(text.substring(1)).toLowerCase().contains(ruleSearch)) return; - String infoText = text.substring(1) + ".info"; - var cell = current.check(text, cons).checked(prov.get()).update(a -> a.setDisabled(!condition.get())).padRight(100f); - if(Core.bundle.has(infoText)){ - cell.tooltip(text + ".info"); - } + var cell = current.check(text, cons).checked(prov.get()).update(a -> a.setDisabled(!condition.get())); cell.get().left(); + ruleInfo(cell, text); current.row(); } + public void ruleInfo(Cell cell, String text){ + if(Core.bundle.has(text.substring(1) + ".info")){ + if(mobile){ + Table table = new Table(); + table.add(cell.get()).left().expandX().fillX(); + cell.clearElement(); + table.button(Icon.infoSmall, () -> ui.showInfo(text + ".info")).size(32f).padRight(24f).right(); + cell.setElement(table).left().expandX().fillX(); + }else{ + cell.tooltip(text + ".info"); + } + } + } + Cell field(Table table, float value, Floatc setter){ return table.field(Strings.autoFixed(value, 2), v -> setter.get(Strings.parseFloat(v))) .valid(Strings::canParsePositiveFloat)