Partial 7.0 merge - API preview
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package mindustry.ui.dialogs;
|
||||
|
||||
import arc.*;
|
||||
import arc.func.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.Texture.*;
|
||||
import arc.graphics.g2d.*;
|
||||
@@ -11,8 +12,11 @@ import arc.scene.ui.*;
|
||||
import arc.scene.ui.ImageButton.*;
|
||||
import arc.scene.ui.TextButton.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.scene.utils.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.ctype.*;
|
||||
import mindustry.game.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
@@ -20,18 +24,27 @@ import mindustry.input.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
|
||||
import java.util.regex.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
|
||||
public class SchematicsDialog extends BaseDialog{
|
||||
private static final float tagh = 42f;
|
||||
private SchematicInfoDialog info = new SchematicInfoDialog();
|
||||
private Schematic firstSchematic;
|
||||
private String search = "";
|
||||
private TextField searchField;
|
||||
private Runnable rebuildPane = () -> {}, rebuildTags = () -> {};
|
||||
private Pattern ignoreSymbols = Pattern.compile("[`~!@#$%^&*()-_=+{}|;:'\",<.>/?]");
|
||||
private Seq<String> tags, selectedTags = new Seq<>();
|
||||
private boolean checkedTags;
|
||||
|
||||
public SchematicsDialog(){
|
||||
super("@schematics");
|
||||
Core.assets.load("sprites/schematic-background.png", Texture.class).loaded = t -> ((Texture)t).setWrap(TextureWrap.repeat);
|
||||
|
||||
tags = Core.settings.getJson("schematic-tags", Seq.class, String.class, Seq::new);
|
||||
|
||||
shouldPause = true;
|
||||
addCloseButton();
|
||||
buttons.button("@schematic.import", Icon.download, this::showImport);
|
||||
@@ -40,8 +53,12 @@ public class SchematicsDialog extends BaseDialog{
|
||||
}
|
||||
|
||||
void setup(){
|
||||
if(!checkedTags){
|
||||
checkTags();
|
||||
checkedTags = true;
|
||||
}
|
||||
|
||||
search = "";
|
||||
Runnable[] rebuildPane = {null};
|
||||
|
||||
cont.top();
|
||||
cont.clear();
|
||||
@@ -51,15 +68,46 @@ public class SchematicsDialog extends BaseDialog{
|
||||
s.image(Icon.zoom);
|
||||
searchField = s.field(search, res -> {
|
||||
search = res;
|
||||
rebuildPane[0].run();
|
||||
rebuildPane.run();
|
||||
}).growX().get();
|
||||
}).fillX().padBottom(4);
|
||||
|
||||
cont.row();
|
||||
|
||||
cont.table(in -> {
|
||||
in.left();
|
||||
in.add("@schematic.tags").padRight(4);
|
||||
|
||||
//tags (no scroll pane visible)
|
||||
in.pane(Styles.nonePane, t -> {
|
||||
rebuildTags = () -> {
|
||||
t.clearChildren();
|
||||
t.left();
|
||||
|
||||
t.defaults().pad(2).height(tagh);
|
||||
for(var tag : tags){
|
||||
t.button(tag, Styles.togglet, () -> {
|
||||
if(selectedTags.contains(tag)){
|
||||
selectedTags.remove(tag);
|
||||
}else{
|
||||
selectedTags.add(tag);
|
||||
}
|
||||
rebuildPane.run();
|
||||
}).checked(selectedTags.contains(tag)).with(c -> c.getLabel().setWrap(false));
|
||||
}
|
||||
};
|
||||
rebuildTags.run();
|
||||
}).fillX().height(tagh).get().setScrollingDisabled(false, true);
|
||||
|
||||
in.button(Icon.pencilSmall, () -> {
|
||||
showAllTags();
|
||||
}).size(tagh).pad(2).tooltip("@schematic.edittags");
|
||||
}).height(tagh).fillX();
|
||||
|
||||
cont.row();
|
||||
|
||||
cont.pane(t -> {
|
||||
t.top();
|
||||
t.margin(20f);
|
||||
|
||||
t.update(() -> {
|
||||
if(Core.input.keyTap(Binding.chat) && Core.scene.getKeyboardFocus() == searchField && firstSchematic != null){
|
||||
@@ -72,18 +120,20 @@ public class SchematicsDialog extends BaseDialog{
|
||||
}
|
||||
});
|
||||
|
||||
rebuildPane[0] = () -> {
|
||||
rebuildPane = () -> {
|
||||
int cols = Math.max((int)(Core.graphics.getWidth() / Scl.scl(230)), 1);
|
||||
|
||||
t.clear();
|
||||
int i = 0;
|
||||
String regex = "[`~!@#$%^&*()-_=+{}|;:'\",<.>/?]";
|
||||
String searchString = search.toLowerCase().replaceAll(regex, " ");
|
||||
String searchString = ignoreSymbols.matcher(search.toLowerCase()).replaceAll("");
|
||||
|
||||
firstSchematic = null;
|
||||
|
||||
for(Schematic s : schematics.all()){
|
||||
if(!search.isEmpty() && !s.name().toLowerCase().replaceAll(regex, " ").contains(searchString)) continue;
|
||||
//make sure *tags* fit
|
||||
if(selectedTags.any() && !s.labels.containsAll(selectedTags)) continue;
|
||||
//make sure search fits
|
||||
if(!search.isEmpty() && !ignoreSymbols.matcher(s.name().toLowerCase()).replaceAll("").contains(searchString)) continue;
|
||||
if(firstSchematic == null) firstSchematic = s;
|
||||
|
||||
Button[] sel = {null};
|
||||
@@ -106,20 +156,27 @@ public class SchematicsDialog extends BaseDialog{
|
||||
|
||||
buttons.button(Icon.pencil, style, () -> {
|
||||
new Dialog("@schematic.rename"){{
|
||||
setFillParent(true);
|
||||
|
||||
cont.margin(30);
|
||||
|
||||
cont.add("@schematic.tags").padRight(6f);
|
||||
cont.table(tags -> buildTags(s, tags, false)).maxWidth(400f).fillX().left().row();
|
||||
|
||||
cont.margin(30).add("@name").padRight(6f);
|
||||
TextField nameField = cont.field(s.name(), null).size(400f, 55f).addInputDialog().get();
|
||||
TextField nameField = cont.field(s.name(), null).size(400f, 55f).addInputDialog().left().get();
|
||||
|
||||
cont.row();
|
||||
|
||||
cont.margin(30).add("@editor.description").padRight(6f);
|
||||
TextField descripionField = cont.area(s.description(), Styles.areaField, t -> {}).size(400f, 140f).addInputDialog().get();
|
||||
TextField descField = cont.area(s.description(), Styles.areaField, t -> {}).size(400f, 140f).left().addInputDialog().get();
|
||||
|
||||
Runnable accept = () -> {
|
||||
s.tags.put("name", nameField.getText());
|
||||
s.tags.put("description", descripionField.getText());
|
||||
s.tags.put("description", descField.getText());
|
||||
s.save();
|
||||
hide();
|
||||
rebuildPane[0].run();
|
||||
rebuildPane.run();
|
||||
};
|
||||
|
||||
buttons.defaults().size(120, 54).pad(4);
|
||||
@@ -127,7 +184,7 @@ public class SchematicsDialog extends BaseDialog{
|
||||
buttons.button("@cancel", this::hide);
|
||||
|
||||
keyDown(KeyCode.enter, () -> {
|
||||
if(!nameField.getText().isEmpty() && Core.scene.getKeyboardFocus() != descripionField){
|
||||
if(!nameField.getText().isEmpty() && Core.scene.getKeyboardFocus() != descField){
|
||||
accept.run();
|
||||
}
|
||||
});
|
||||
@@ -146,7 +203,7 @@ public class SchematicsDialog extends BaseDialog{
|
||||
}else{
|
||||
ui.showConfirm("@confirm", "@schematic.delete.confirm", () -> {
|
||||
schematics.remove(s);
|
||||
rebuildPane[0].run();
|
||||
rebuildPane.run();
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -188,8 +245,8 @@ public class SchematicsDialog extends BaseDialog{
|
||||
}
|
||||
};
|
||||
|
||||
rebuildPane[0].run();
|
||||
}).get().setScrollingDisabled(true, false);
|
||||
rebuildPane.run();
|
||||
}).grow().get().setScrollingDisabled(true, false);
|
||||
}
|
||||
|
||||
public void showInfo(Schematic schematic){
|
||||
@@ -212,6 +269,7 @@ public class SchematicsDialog extends BaseDialog{
|
||||
schematics.add(s);
|
||||
setup();
|
||||
ui.showInfoFade("@schematic.saved");
|
||||
checkTags(s);
|
||||
showInfo(s);
|
||||
}catch(Throwable e){
|
||||
ui.showException(e);
|
||||
@@ -227,6 +285,7 @@ public class SchematicsDialog extends BaseDialog{
|
||||
schematics.add(s);
|
||||
setup();
|
||||
showInfo(s);
|
||||
checkTags(s);
|
||||
}catch(Exception e){
|
||||
ui.showException(e);
|
||||
}
|
||||
@@ -281,6 +340,315 @@ public class SchematicsDialog extends BaseDialog{
|
||||
Core.scene.setKeyboardFocus(searchField);
|
||||
}
|
||||
|
||||
|
||||
//adds all new tags to the global list of tags
|
||||
//alternatively, unknown tags could be discarded on import?
|
||||
void checkTags(){
|
||||
ObjectSet<String> encountered = new ObjectSet<>();
|
||||
encountered.addAll(tags);
|
||||
for(Schematic s : schematics.all()){
|
||||
for(var tag : s.labels){
|
||||
if(encountered.add(tag)){
|
||||
tags.add(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//adds any new tags found to the global tag list
|
||||
//TODO remove tags from it instead?
|
||||
void checkTags(Schematic s){
|
||||
boolean any = false;
|
||||
for(var tag : s.labels){
|
||||
if(!tags.contains(tag)){
|
||||
tags.add(tag);
|
||||
any = true;
|
||||
}
|
||||
}
|
||||
if(any){
|
||||
rebuildTags.run();
|
||||
}
|
||||
}
|
||||
|
||||
void tagsChanged(){
|
||||
rebuildTags.run();
|
||||
if(selectedTags.any()){
|
||||
rebuildPane.run();
|
||||
}
|
||||
|
||||
Core.settings.putJson("schematic-tags", String.class, tags);
|
||||
}
|
||||
|
||||
void addTag(Schematic s, String tag){
|
||||
s.labels.add(tag);
|
||||
s.save();
|
||||
tagsChanged();
|
||||
}
|
||||
|
||||
void removeTag(Schematic s, String tag){
|
||||
s.labels.remove(tag);
|
||||
s.save();
|
||||
tagsChanged();
|
||||
}
|
||||
|
||||
//shows a dialog for creating a new tag
|
||||
void showNewTag(Cons<String> result){
|
||||
ui.showTextInput("@schematic.addtag", "", "", out -> {
|
||||
if(tags.contains(out)){
|
||||
ui.showInfo("@schematic.tagexists");
|
||||
}else{
|
||||
tags.add(out);
|
||||
tagsChanged();
|
||||
result.get(out);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void showNewIconTag(Cons<String> cons){
|
||||
new Dialog(){{
|
||||
closeOnBack();
|
||||
setFillParent(true);
|
||||
|
||||
cont.pane(t -> {
|
||||
resized(true, () -> {
|
||||
t.clearChildren();
|
||||
t.marginRight(19f);
|
||||
t.defaults().size(48f);
|
||||
|
||||
int cols = (int)Math.min(20, Core.graphics.getWidth() / 52f);
|
||||
|
||||
/*
|
||||
int i = 0;
|
||||
for(var key : defaultIcons){
|
||||
var value = Icon.icons.get(key);
|
||||
|
||||
t.button(value, Styles.cleari, () -> {
|
||||
sector.info.icon = key;
|
||||
sector.info.contentIcon = null;
|
||||
sector.saveInfo();
|
||||
hide();
|
||||
updateSelected();
|
||||
}).checked(key.equals(sector.info.icon));
|
||||
|
||||
if(++i % cols == 0) t.row();
|
||||
}*/
|
||||
|
||||
int i = 0;
|
||||
|
||||
for(ContentType ctype : defaultContentIcons){
|
||||
t.row();
|
||||
t.image().colspan(cols).growX().width(Float.NEGATIVE_INFINITY).height(3f).color(Pal.accent);
|
||||
t.row();
|
||||
|
||||
i = 0;
|
||||
for(UnlockableContent u : content.getBy(ctype).<UnlockableContent>as()){
|
||||
if(!u.isHidden() && u.unlockedNow() && u.hasEmoji() && !tags.contains(u.emoji())){
|
||||
t.button(new TextureRegionDrawable(u.uiIcon), Styles.cleari, iconMed, () -> {
|
||||
String out = u.emoji() + "";
|
||||
|
||||
tags.add(out);
|
||||
tagsChanged();
|
||||
cons.get(out);
|
||||
|
||||
hide();
|
||||
});
|
||||
|
||||
if(++i % cols == 0) t.row();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
buttons.button("@back", Icon.left, this::hide).size(210f, 64f);
|
||||
}}.show();
|
||||
}
|
||||
|
||||
void showAllTags(){
|
||||
var dialog = new BaseDialog("@schematic.edittags");
|
||||
dialog.addCloseButton();
|
||||
Runnable[] rebuild = {null};
|
||||
dialog.cont.pane(p -> {
|
||||
rebuild[0] = () -> {
|
||||
p.clearChildren();
|
||||
p.defaults().fillX().left();
|
||||
|
||||
float sum = 0f;
|
||||
Table current = new Table().left();
|
||||
|
||||
for(var tag : tags){
|
||||
|
||||
var next = new Table(Tex.button, n -> {
|
||||
n.add(tag).padRight(4);
|
||||
|
||||
n.add().growX();
|
||||
n.defaults().size(30f);
|
||||
|
||||
//delete
|
||||
n.button(Icon.cancelSmall, Styles.emptyi, () -> {
|
||||
ui.showConfirm("@schematic.tagdelconfirm", () -> {
|
||||
for(Schematic s : schematics.all()){
|
||||
if(s.labels.any()){
|
||||
s.labels.remove(tag);
|
||||
s.save();
|
||||
}
|
||||
}
|
||||
selectedTags.remove(tag);
|
||||
tags.remove(tag);
|
||||
tagsChanged();
|
||||
rebuildPane.run();
|
||||
rebuild[0].run();
|
||||
});
|
||||
});
|
||||
//rename
|
||||
n.button(Icon.pencilSmall, Styles.emptyi, () -> {
|
||||
ui.showTextInput("@schematic.renametag", "@name", tag, result -> {
|
||||
//same tag, nothing was renamed
|
||||
if(result.equals(tag)) return;
|
||||
|
||||
if(tags.contains(result)){
|
||||
ui.showInfo("@schematic.tagexists");
|
||||
}else{
|
||||
for(Schematic s : schematics.all()){
|
||||
if(s.labels.any()){
|
||||
s.labels.replace(tag, result);
|
||||
s.save();
|
||||
}
|
||||
}
|
||||
selectedTags.replace(tag, result);
|
||||
tags.replace(tag, result);
|
||||
tagsChanged();
|
||||
rebuild[0].run();
|
||||
}
|
||||
});
|
||||
});
|
||||
//move
|
||||
n.button(Icon.upSmall, Styles.emptyi, () -> {
|
||||
int idx = tags.indexOf(tag);
|
||||
if(idx > 0){
|
||||
tags.swap(idx, idx - 1);
|
||||
tagsChanged();
|
||||
rebuild[0].run();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
next.pack();
|
||||
float w = next.getPrefWidth() + Scl.scl(6f);
|
||||
|
||||
if(w + sum >= Core.graphics.getWidth() * (Core.graphics.isPortrait() ? 1f : 0.8f)){
|
||||
p.add(current).row();
|
||||
current = new Table();
|
||||
current.left();
|
||||
current.add(next).height(tagh).pad(2);
|
||||
sum = 0;
|
||||
}else{
|
||||
current.add(next).height(tagh).pad(2);
|
||||
}
|
||||
|
||||
sum += w;
|
||||
}
|
||||
|
||||
if(sum > 0){
|
||||
p.add(current).row();
|
||||
}
|
||||
|
||||
p.table(t -> {
|
||||
t.left().defaults().fillX().height(tagh).pad(2);
|
||||
|
||||
t.button("@schematic.texttag", Icon.add, () -> showNewTag(res -> rebuild[0].run())).wrapLabel(false).get().getLabelCell().padLeft(5);
|
||||
t.button("@schematic.icontag", Icon.add, () -> showNewIconTag(res -> rebuild[0].run())).wrapLabel(false).get().getLabelCell().padLeft(5);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
resized(true, rebuild[0]);
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
void buildTags(Schematic schem, Table t){
|
||||
buildTags(schem, t, true);
|
||||
}
|
||||
|
||||
void buildTags(Schematic schem, Table t, boolean name){
|
||||
t.clearChildren();
|
||||
t.left();
|
||||
|
||||
//sort by order in the main target array. the complexity of this is probably awful
|
||||
schem.labels.sort(s -> tags.indexOf(s));
|
||||
|
||||
if(name) t.add("@schematic.tags").padRight(4);
|
||||
t.pane(s -> {
|
||||
s.left();
|
||||
s.defaults().pad(3).height(tagh);
|
||||
for(var tag : schem.labels){
|
||||
s.table(Tex.button, i -> {
|
||||
i.add(tag).padRight(4).height(tagh).labelAlign(Align.center);
|
||||
i.button(Icon.cancelSmall, Styles.emptyi, () -> {
|
||||
removeTag(schem, tag);
|
||||
buildTags(schem, t, name);
|
||||
}).size(tagh).padRight(-9f).padLeft(-9f);
|
||||
});
|
||||
}
|
||||
|
||||
}).fillX().left().height(tagh).get().setScrollingDisabled(false, true);
|
||||
|
||||
t.button(Icon.addSmall, () -> {
|
||||
var dialog = new BaseDialog("@schematic.addtag");
|
||||
dialog.addCloseButton();
|
||||
dialog.cont.pane(p -> resized(true, () -> {
|
||||
p.clearChildren();
|
||||
|
||||
float sum = 0f;
|
||||
Table current = new Table().left();
|
||||
for(var tag : tags){
|
||||
if(schem.labels.contains(tag)) continue;
|
||||
|
||||
var next = Elem.newButton(tag, () -> {
|
||||
addTag(schem, tag);
|
||||
buildTags(schem, t, name);
|
||||
dialog.hide();
|
||||
});
|
||||
next.getLabel().setWrap(false);
|
||||
|
||||
next.pack();
|
||||
float w = next.getPrefWidth() + Scl.scl(6f);
|
||||
|
||||
if(w + sum >= Core.graphics.getWidth() * (Core.graphics.isPortrait() ? 1f : 0.8f)){
|
||||
p.add(current).row();
|
||||
current = new Table();
|
||||
current.left();
|
||||
current.add(next).height(tagh).pad(2);
|
||||
sum = 0;
|
||||
}else{
|
||||
current.add(next).height(tagh).pad(2);
|
||||
}
|
||||
|
||||
sum += w;
|
||||
}
|
||||
|
||||
if(sum > 0){
|
||||
p.add(current).row();
|
||||
}
|
||||
|
||||
Cons<String> handleTag = res -> {
|
||||
dialog.hide();
|
||||
addTag(schem, res);
|
||||
buildTags(schem, t, name);
|
||||
};
|
||||
|
||||
p.row();
|
||||
|
||||
p.table(v -> {
|
||||
v.left().defaults().fillX().height(tagh).pad(2);
|
||||
v.button("@schematic.texttag", Icon.add, () -> showNewTag(handleTag)).wrapLabel(false).get().getLabelCell().padLeft(4);
|
||||
v.button("@schematic.icontag", Icon.add, () -> showNewIconTag(handleTag)).wrapLabel(false).get().getLabelCell().padLeft(4);
|
||||
});
|
||||
}));
|
||||
dialog.show();
|
||||
}).size(tagh).tooltip("@schematic.addtag");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialog show(){
|
||||
super.show();
|
||||
@@ -298,6 +666,7 @@ public class SchematicsDialog extends BaseDialog{
|
||||
public Color borderColor = Pal.gray;
|
||||
|
||||
private Schematic schematic;
|
||||
private Texture lastTexture;
|
||||
boolean set;
|
||||
|
||||
public SchematicImage(Schematic s){
|
||||
@@ -320,6 +689,8 @@ public class SchematicsDialog extends BaseDialog{
|
||||
if(!set){
|
||||
Core.app.post(this::setPreview);
|
||||
set = true;
|
||||
}else if(lastTexture != null && lastTexture.isDisposed()){
|
||||
set = wasSet = false;
|
||||
}
|
||||
|
||||
Texture background = Core.assets.get("sprites/schematic-background.png", Texture.class);
|
||||
@@ -346,13 +717,13 @@ public class SchematicsDialog extends BaseDialog{
|
||||
}
|
||||
|
||||
private void setPreview(){
|
||||
TextureRegionDrawable draw = new TextureRegionDrawable(new TextureRegion(schematics.getPreview(schematic)));
|
||||
TextureRegionDrawable draw = new TextureRegionDrawable(new TextureRegion(lastTexture = schematics.getPreview(schematic)));
|
||||
setDrawable(draw);
|
||||
setScaling(Scaling.fit);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SchematicInfoDialog extends BaseDialog{
|
||||
public class SchematicInfoDialog extends BaseDialog{
|
||||
|
||||
SchematicInfoDialog(){
|
||||
super("");
|
||||
@@ -366,6 +737,8 @@ public class SchematicsDialog extends BaseDialog{
|
||||
|
||||
cont.add(Core.bundle.format("schematic.info", schem.width, schem.height, schem.tiles.size)).color(Color.lightGray);
|
||||
cont.row();
|
||||
cont.table(tags -> buildTags(schem, tags)).fillX().left().row();
|
||||
cont.row();
|
||||
cont.add(new SchematicImage(schem)).maxSize(800f);
|
||||
cont.row();
|
||||
|
||||
@@ -373,7 +746,7 @@ public class SchematicsDialog extends BaseDialog{
|
||||
cont.table(r -> {
|
||||
int i = 0;
|
||||
for(ItemStack s : arr){
|
||||
r.image(s.item.icon(Cicon.small)).left();
|
||||
r.image(s.item.uiIcon).left().size(iconMed);
|
||||
r.label(() -> {
|
||||
Building core = player.core();
|
||||
if(core == null || state.rules.infiniteResources || core.items.has(s.item, s.amount)) return "[lightgray]" + s.amount + "";
|
||||
|
||||
Reference in New Issue
Block a user