diff --git a/core/src/mindustry/editor/MapObjectivesDialog.java b/core/src/mindustry/editor/MapObjectivesDialog.java index ab781c7419..b1be72ecfc 100644 --- a/core/src/mindustry/editor/MapObjectivesDialog.java +++ b/core/src/mindustry/editor/MapObjectivesDialog.java @@ -17,6 +17,7 @@ import mindustry.game.MapObjectives.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.io.*; +import mindustry.logic.*; import mindustry.type.*; import mindustry.ui.*; import mindustry.ui.dialogs.*; @@ -280,6 +281,15 @@ public class MapObjectivesDialog extends BaseDialog{ }); })); + setInterpreter(Alignment.class, int.class, (cont, name, type, field, remover, indexer, get, set) -> { + Alignment align = field.getAnnotation(Alignment.class); + name(cont, name, remover, indexer); + cont.button(b -> { + b.label(() -> LStatement.alignToName.get(get.get(), "center")); + b.clicked(() -> LStatement.showAlignSelect(b, get.get(), set::get, align.hor(), align.ver())); + }, () -> {}); + }); + // Types that use the default interpreter. It would be nice if all types could use it, but I don't know how to reliably prevent classes like [? extends Content] from using it. for(var obj : MapObjectives.allObjectiveTypes) setInterpreter(obj.get().getClass(), defaultInterpreter()); for(var mark : MapObjectives.allMarkerTypes) setInterpreter(mark.get().getClass(), defaultInterpreter()); diff --git a/core/src/mindustry/entities/comp/WorldLabelComp.java b/core/src/mindustry/entities/comp/WorldLabelComp.java index 4b7401826b..a98dd27fbf 100644 --- a/core/src/mindustry/entities/comp/WorldLabelComp.java +++ b/core/src/mindustry/entities/comp/WorldLabelComp.java @@ -31,10 +31,10 @@ public abstract class WorldLabelComp implements Posc, Drawc, Syncc{ @Override public void draw(){ - drawAt(text, x, y, z, flags, fontSize); + drawAt(text, x, y, z, flags, fontSize, Align.center, Align.center); } - public static void drawAt(String text, float x, float y, float layer, int flags, float fontSize){ + public static void drawAt(String text, float x, float y, float layer, int flags, float fontSize, int align, int lineAlign){ Draw.z(layer); float z = Drawf.text(); @@ -46,14 +46,32 @@ public abstract class WorldLabelComp implements Posc, Drawc, Syncc{ font.getData().setScale(0.25f / Scl.scl(1f) * fontSize); layout.setText(font, text); + int border = (flags & flagBackground) != 0 ? 1 : 0; + + if(Align.isBottom(align)){ + y += layout.height + border * 1.5f; + }else if(Align.isTop(align)){ + y -= border * 1.5f; + }else{ + y += layout.height / 2; + } + + if(Align.isLeft(align)){ + x += layout.width / 2 + border; + }else if(Align.isRight(align)){ + x -= layout.width / 2 + border; + } + if((flags & flagBackground) != 0){ Draw.color(0f, 0f, 0f, 0.3f); Fill.rect(x, y - layout.height / 2, layout.width + 2, layout.height + 3); Draw.color(); } + float tx = Align.isLeft(lineAlign) ? -layout.width * 0.5f : Align.isRight(lineAlign) ? layout.width * 0.5f : 0; + font.setColor(Color.white); - font.draw(text, x, y, 0, Align.center, false); + font.draw(text, x + tx, y, 0, lineAlign, false); Draw.reset(); Pools.free(layout); diff --git a/core/src/mindustry/game/MapObjectives.java b/core/src/mindustry/game/MapObjectives.java index 31fac3c1e0..c91bdd2d8e 100644 --- a/core/src/mindustry/game/MapObjectives.java +++ b/core/src/mindustry/game/MapObjectives.java @@ -757,6 +757,8 @@ public class MapObjectives implements Iterable, Eachable, Eachable, Eachable, Eachable fontSize = (float)p1; case textHeight -> textHeight = (float)p1; + case textAlign -> textAlign = (int)p1; + case lineAlign -> lineAlign = (int)p1; case outline -> flags = (byte)Pack.bitmask(flags, WorldLabel.flagOutline, !Mathf.equal((float)p1, 0f)); case labelFlags -> flags = (byte)Pack.bitmask(flags, WorldLabel.flagBackground, !Mathf.equal((float)p1, 0f)); case radius -> radius = (float)p1; @@ -980,6 +993,9 @@ public class MapObjectives implements Iterable, Eachable, Eachable, Eachable fontSize = (float)p1; + case textAlign -> textAlign = (int)p1; + case lineAlign -> lineAlign = (int)p1; case outline -> flags = (byte)Pack.bitmask(flags, WorldLabel.flagOutline, !Mathf.equal((float)p1, 0f)); case labelFlags -> flags = (byte)Pack.bitmask(flags, WorldLabel.flagBackground, !Mathf.equal((float)p1, 0f)); } @@ -1317,6 +1335,14 @@ public class MapObjectives implements Iterable, Eachable, Eachable put("@" + name, align)); + logicIdToContent = new UnlockableContent[ContentType.all.length][]; contentIdToLogicId = new int[ContentType.all.length][]; diff --git a/core/src/mindustry/logic/LExecutor.java b/core/src/mindustry/logic/LExecutor.java index f55af42f6b..0609458a31 100644 --- a/core/src/mindustry/logic/LExecutor.java +++ b/core/src/mindustry/logic/LExecutor.java @@ -897,7 +897,7 @@ public class LExecutor{ int advance = (int)data.spaceXadvance, lineHeight = (int)data.lineHeight; int xOffset, yOffset; - int align = p1.id; //p1 is not a variable, it's a raw align value. what a massive hack + int align = p1.numi(); int maxWidth = 0, lines = 1, lineWidth = 0; for(int i = 0; i < str.length(); i++){ diff --git a/core/src/mindustry/logic/LMarkerControl.java b/core/src/mindustry/logic/LMarkerControl.java index 57780d8187..6de27aa378 100644 --- a/core/src/mindustry/logic/LMarkerControl.java +++ b/core/src/mindustry/logic/LMarkerControl.java @@ -18,6 +18,8 @@ public enum LMarkerControl{ flushText("fetch"), fontSize("size"), textHeight("height"), + textAlign("align"), + lineAlign("align"), labelFlags("background", "outline"), texture("printFlush", "name"), textureSize("width", "height"), diff --git a/core/src/mindustry/logic/LStatement.java b/core/src/mindustry/logic/LStatement.java index a7a384084f..0557d087b6 100644 --- a/core/src/mindustry/logic/LStatement.java +++ b/core/src/mindustry/logic/LStatement.java @@ -23,6 +23,25 @@ import static mindustry.logic.LCanvas.*; * A statement is an intermediate representation of an instruction, to be used mostly in UI. * Contains all relevant variable information. */ public abstract class LStatement{ + + private static final String[] aligns = {"topLeft", "top", "topRight", "left", "center", "right", "bottomLeft", "bottom", "bottomRight"}; + public static final ObjectMap nameToAlign = ObjectMap.of( + "center", Align.center, + "top", Align.top, + "bottom", Align.bottom, + "left", Align.left, + "right", Align.right, + "topLeft", Align.topLeft, + "topRight", Align.topRight, + "bottomLeft", Align.bottomLeft, + "bottomRight", Align.bottomRight + ); + public static final IntMap alignToName = new IntMap<>(); + + static { + nameToAlign.each((k, v) -> alignToName.put(v, k)); + } + public transient @Nullable StatementElem elem; public abstract void build(Table table); @@ -175,7 +194,36 @@ public abstract class LStatement{ showSelect(b, values, current, getter, 4, c -> {}); } - protected void showSelectTable(Button b, Cons2 hideCons){ + protected void fieldAlignSelect(Table t, Prov get, Cons set, boolean hor, boolean ver) { + t.button(b -> { + b.image(Icon.pencilSmall); + b.clicked(() -> { + var current = get.get(); + showAlignSelect(b, current.startsWith("@") ? nameToAlign.get(current.substring(1), -1) : -1, align -> set.get("@" + alignToName.get(align)), hor, ver); + }); + }, Styles.logict, () -> {}).size(40f).color(t.color).left().padLeft(-10); + } + + public static void showAlignSelect(Button b, int current, Intc setter, boolean hor, boolean ver) { + showSelectTable(b, (t, hide) -> { + t.defaults().size(150f, 40f); + + int i = 0; + for(String align : aligns){ + int val = nameToAlign.get(align); + if(!hor && !Align.isCenterHorizontal(val)) continue; + if(!ver && !Align.isCenterVertical(val)) continue; + t.button(align, Styles.logicTogglet, () -> { + setter.get(val); + hide.run(); + }).checked(current == nameToAlign.get(align)).grow(); + + if (++i % 3 == 0) t.row(); + } + }); + } + + protected static void showSelectTable(Button b, Cons2 hideCons){ Table t = new Table(Tex.paneSolid){ @Override public float getPrefHeight(){ diff --git a/core/src/mindustry/logic/LStatements.java b/core/src/mindustry/logic/LStatements.java index 45e26c36e6..0cf38a0580 100644 --- a/core/src/mindustry/logic/LStatements.java +++ b/core/src/mindustry/logic/LStatements.java @@ -6,7 +6,6 @@ import arc.graphics.*; import arc.scene.style.*; import arc.scene.ui.*; import arc.scene.ui.layout.*; -import arc.struct.*; import arc.util.*; import mindustry.*; import mindustry.annotations.Annotations.*; @@ -123,19 +122,6 @@ public class LStatements{ @RegisterStatement("draw") public static class DrawStatement extends LStatement{ - static final String[] aligns = {"center", "top", "bottom", "left", "right", "topLeft", "topRight", "bottomLeft", "bottomRight"}; - //yes, boxing Integer is gross but this is easier to construct and Integers <128 don't allocate anyway - static final ObjectMap nameToAlign = ObjectMap.of( - "center", Align.center, - "top", Align.top, - "bottom", Align.bottom, - "left", Align.left, - "right", Align.right, - "topLeft", Align.topLeft, - "topRight", Align.topRight, - "bottomLeft", Align.bottomLeft, - "bottomRight", Align.bottomRight - ); public GraphicsType type = GraphicsType.clear; public String x = "0", y = "0", p1 = "0", p2 = "0", p3 = "0", p4 = "0"; @@ -165,7 +151,7 @@ public class LStatements{ } if(type == GraphicsType.print){ - p1 = "bottomLeft"; + p1 = "@bottomLeft"; } rebuild(table); @@ -253,13 +239,11 @@ public class LStatements{ row(s); s.add("align "); - - s.button(b -> { - b.label(() -> nameToAlign.containsKey(p1) ? p1 : "bottomLeft"); - b.clicked(() -> showSelect(b, aligns, p1, t -> { - p1 = t; - }, 2, cell -> cell.size(165, 50))); - }, Styles.logict, () -> {}).size(165, 40).color(s.color).left().padLeft(2); + fields(s, "align", p1, v -> p1 = v); + fieldAlignSelect(s, () -> p1, v -> { + p1 = v; + rebuild(table); + }, true, true); } case translate, scale -> { fields(s, "x", x, v -> x = v); @@ -278,12 +262,15 @@ public class LStatements{ if(type == GraphicsType.color && p2.equals("0")){ p2 = "255"; } + + if(type == GraphicsType.print && nameToAlign.get(p1) != null){ + p1 = "@" + p1; + } } @Override public LInstruction build(LAssembler builder){ - return new DrawI((byte)type.ordinal(), builder.var(x), builder.var(y), - type == GraphicsType.print ? new LVar(p1, nameToAlign.get(p1, Align.bottomLeft), true) : builder.var(p1), builder.var(p2), builder.var(p3), builder.var(p4)); + return new DrawI((byte)type.ordinal(), builder.var(x), builder.var(y), builder.var(p1), builder.var(p2), builder.var(p3), builder.var(p4)); } @Override @@ -2399,6 +2386,11 @@ public class LStatements{ }).width(240f).left(); })); }, Styles.logict, () -> {}).size(40f).padLeft(-11).color(table.color); + }else if(type == LMarkerControl.textAlign || type == LMarkerControl.lineAlign){ + fieldAlignSelect(t, () -> p1, v -> { + p1 = v; + rebuild(table); + }, true, type != LMarkerControl.lineAlign); } });