diff --git a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIFactory.java b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIFactory.java index b71226309da..bf073ddcce4 100644 --- a/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIFactory.java +++ b/src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIFactory.java @@ -19,11 +19,17 @@ import net.minecraft.util.text.TextFormatting; import com.cleanroommc.modularui.api.drawable.IDrawable; +import com.cleanroommc.modularui.api.drawable.IHoverable; import com.cleanroommc.modularui.api.drawable.IKey; +import com.cleanroommc.modularui.api.drawable.IRichTextBuilder; +import com.cleanroommc.modularui.api.widget.ITooltip; import com.cleanroommc.modularui.api.widget.IWidget; -import com.cleanroommc.modularui.drawable.text.DynamicKey; +import com.cleanroommc.modularui.drawable.text.RichText; import com.cleanroommc.modularui.factory.PosGuiData; import com.cleanroommc.modularui.screen.ModularPanel; +import com.cleanroommc.modularui.screen.RichTooltip; +import com.cleanroommc.modularui.screen.viewport.GuiContext; +import com.cleanroommc.modularui.theme.WidgetTheme; import com.cleanroommc.modularui.utils.Alignment; import com.cleanroommc.modularui.value.sync.BooleanSyncValue; import com.cleanroommc.modularui.value.sync.IntSyncValue; @@ -33,14 +39,13 @@ import com.cleanroommc.modularui.widget.ScrollWidget; import com.cleanroommc.modularui.widget.Widget; import com.cleanroommc.modularui.widget.scroll.VerticalScrollData; +import com.cleanroommc.modularui.widget.sizer.Area; +import com.cleanroommc.modularui.widget.sizer.Box; import com.cleanroommc.modularui.widgets.CycleButtonWidget; import com.cleanroommc.modularui.widgets.ProgressWidget; +import com.cleanroommc.modularui.widgets.RichTextWidget; import com.cleanroommc.modularui.widgets.SlotGroupWidget; -import com.cleanroommc.modularui.widgets.layout.Column; import com.cleanroommc.modularui.widgets.layout.Flow; -import com.cleanroommc.modularui.widgets.layout.Row; -import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -48,14 +53,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.function.BiFunction; import java.util.function.BooleanSupplier; import java.util.function.Consumer; import java.util.function.DoubleSupplier; -import java.util.function.Function; import java.util.function.IntSupplier; import java.util.function.Supplier; +import static com.cleanroommc.modularui.api.drawable.IKey.renderer; + public class MultiblockUIFactory { private final MultiblockWithDisplayBase mte; @@ -144,7 +151,7 @@ private Widget createIndicator() { .pos(174 - 5, screenHeight - 18 - 3) .onUpdateListener(w -> w.overlay(getIndicatorOverlay(builder))) .tooltip(tooltip -> tooltip.setAutoUpdate(true)) - .tooltipBuilder(tooltip -> tooltip.addDrawableLines(builder.getTextList())); + .tooltipBuilder(builder::buildTooltip); } private IDrawable getIndicatorOverlay(Builder builder) { @@ -308,27 +315,29 @@ public MultiblockUIFactory customScreen(Supplier> customScreen) protected Widget createScreen(PanelSyncManager syncManager) { final var builder = builder(); this.displayText.accept(builder); - var col = new Column(); - builder.build(col); + RichTextWidget widget = new RichTextWidget(); + builder.buildDisplay(widget); final var compare = builder(); return new ParentWidget<>() .child(createIndicator()) .child(customScreen != null ? customScreen.get() : new ScrollWidget<>(new VerticalScrollData()) .sizeRel(1f) - .child(col.expanded() + .child(widget.sizeRel(1f) + .alignment(Alignment.TopLeft) .margin(4, 4) .onUpdateListener(column -> { // really debating on if the display screen should be its own widget - compare.clear(); + // compare.clear(); this.displayText.accept(compare); - if (!builder.hasChanged(compare) && !dirty) return; - builder.clear(); - column.getChildren().clear(); - this.displayText.accept(builder); - builder.build(column); - resize(column); - dirty = false; + // if (!builder.hasChanged(compare) && !dirty) return; + // builder.clear(); + if (builder.hasChanged(compare)) + widget.markDirty(); + // this.displayText.accept(builder); + // builder.build(column); + // resize(column); + // dirty = false; }))) .background(GTGuiTextures.DISPLAY) .size(190, screenHeight) @@ -465,9 +474,11 @@ protected static Builder builder() { @SuppressWarnings({ "UnusedReturnValue", "unused" }) public static class Builder { - private final List textList; - private Function> widgetFunction = Builder::keyMapper; - private final Int2ObjectMap tooltips = new Int2ObjectArrayMap<>(); + private final RichText text = new RichText(); + private final List>>> textList = new ArrayList<>(); + // private final List textList; + // private Function> widgetFunction = Builder::keyMapper; + // private final Int2ObjectMap tooltips = new Int2ObjectArrayMap<>(); private BooleanSupplier isWorkingEnabled = () -> false; private BooleanSupplier isActive = () -> false; @@ -479,15 +490,15 @@ public static class Builder { private IKey runningKey = IKey.lang("gregtech.multiblock.running").format(TextFormatting.GREEN); private boolean dirty; - protected static Widget keyMapper(IDrawable key) { - return key.asWidget() - .widthRel(1f) - .height(12); - } + // protected static Widget keyMapper(IDrawable key) { + // return key.asWidget() + // .widthRel(1f) + // .height(12); + // } - private Builder() { - this.textList = new ArrayList<>(); - } + // private Builder() { + // this.textList = new ArrayList<>(); + // } public Builder structureFormed(boolean structureFormed) { this.isStructureFormed = structureFormed; @@ -672,11 +683,11 @@ public Builder addWorkingStatusLine() { addKey(KeyUtil.string(() -> { if (!isWorkingEnabled.getAsBoolean()) { - return TextFormatting.GOLD + pausedKey.get(); + return pausedKey.getFormatted(); } else if (isActive.getAsBoolean()) { - return TextFormatting.GREEN + runningKey.get(); + return runningKey.getFormatted(); } else { - return TextFormatting.GRAY + idlingKey.get(); + return idlingKey.getFormatted(); } })); return this; @@ -881,25 +892,25 @@ public Builder addFuelNeededLine(String fuelName, IntSupplier previousRecipeDura /** Insert an empty line into the text list. */ public Builder addEmptyLine() { - addKey(IKey.EMPTY); // this is going to cause problems maybe + this.text.newLine(); return this; } /** Add custom text dynamically, allowing for custom application logic. */ - public Builder addCustom(Consumer> customConsumer) { - List customKeys = new ArrayList<>(); - customConsumer.accept(customKeys); - customKeys.forEach(this::addKey); + public Builder addCustom(Consumer customConsumer) { + // List customKeys = new ArrayList<>(); + customConsumer.accept(this.text); + // customKeys.forEach(this::addKey); return this; } - /** - * @param widgetFunction function to build widgets from keys - */ - public Builder widgetFunction(Function> widgetFunction) { - this.widgetFunction = widgetFunction; - return this; - } + // /** + // * @param widgetFunction function to build widgets from keys + // */ + // public Builder widgetFunction(Function> widgetFunction) { + // this.widgetFunction = widgetFunction; + // return this; + // } protected boolean isEmpty() { return textList.isEmpty(); @@ -909,41 +920,129 @@ protected void clear() { textList.clear(); } - protected void build(ParentWidget parent) { - for (int i = 0; i < textList.size(); i++) { - var line = this.widgetFunction.apply(textList.get(i)); - if (tooltips.containsKey(i)) - line.addTooltipLine(tooltips.get(i)); - parent.child(line); - } + protected void buildDisplay(RichTextWidget parent) { + parent.textBuilder(richText -> this.textList.forEach(t -> t.accept(richText))); + // for (int i = 0; i < textList.size(); i++) { + // var line = this.widgetFunction.apply(textList.get(i)); + // if (tooltips.containsKey(i)) + // line.addTooltipLine(tooltips.get(i)); + // parent.child(line); + // } } - protected List getTextList() { - return Collections.unmodifiableList(textList); + protected void buildTooltip(RichTooltip tooltip) { + this.textList.forEach(t -> t.accept(tooltip)); + // parent.tooltipBuilder(richText -> this.textList.forEach(t -> t.accept(richText))); } - protected boolean hasChanged(Builder other) { - if (textList.size() != other.textList.size()) return true; - for (int i = 0; i < textList.size(); i++) { - IDrawable left = textList.get(i), right = other.textList.get(i); - - // dynamic keys are impossible to check, skip - if (left instanceof DynamicKey && right instanceof DynamicKey) - continue; + protected RichText getTextList() { + // return Collections.unmodifiableList(textList); + return this.text; + } - if (!left.equals(right)) + protected boolean hasChanged(Builder other) { + List cur = text.getStringRepresentation(); + List oth = other.text.getStringRepresentation(); + if (cur.size() != oth.size()) return true; + for (int i = 0; i < cur.size(); i++) { + if (!Objects.equals(cur.get(i), oth.get(i))) return true; } return false; } private void addKey(IDrawable key) { - this.textList.add(key); + // this.text.add(key); + textList.add(richText -> richText.addLine(key)); + // this.textList.add(key); } private void addKey(IDrawable key, IDrawable hover) { - this.tooltips.put(textList.size(), hover); - addKey(key); + // this.text.add(); + // this.tooltips.put(textList.size(), hover); + // addKey(key.asIcon().asHoverable().addTooltipLine(hover)); + addKey(new TestDrawable(key, hover)); + } + } + + private static class TestDrawable implements IHoverable, ITooltip { + + private final IDrawable drawable; + private RichTooltip tooltip; + private final Area area; + + private TestDrawable(IDrawable drawable, IDrawable hover) { + this.drawable = drawable; + this.area = drawable instanceof IKey key ? calculateArea(key) : new Area(); + tooltip().addLine(hover); + } + + private Area calculateArea(IKey key) { + renderer.setSimulate(true); + renderer.setScale(1f); + renderer.draw(key.getFormatted()); + renderer.getMaxWidth(Collections.singletonList(key.getFormatted())); + int h = (int) renderer.getLastWidth(); + int w = (int) renderer.getLastHeight(); + renderer.setSimulate(false); + return new Area(0, 0, w, h); + } + + @Override + public void setRenderedAt(int x, int y) { + this.area.setPos(x, y); + } + + @Override + public Area getRenderedArea() { + return this.area; + } + + @Override + public int getWidth() { + return this.area.w(); + } + + @Override + public int getHeight() { + return this.area.h(); + } + + @Override + public Box getMargin() { + return this.area.getMargin(); + } + + @Override + @Nullable + public RichTooltip getTooltip() { + return tooltip; + } + + @Override + public @NotNull RichTooltip tooltip() { + if (this.tooltip == null) this.tooltip = new RichTooltip(area -> area.set(getRenderedArea())); + return tooltip; + } + + @Override + public TestDrawable tooltip(RichTooltip tooltip) { + this.tooltip = tooltip; + return this; + } + + @Override + public void draw(GuiContext context, int x, int y, int width, int height, WidgetTheme widgetTheme) { + if (drawable instanceof IKey key) { + renderer.setColor(widgetTheme.getTextColor()); + renderer.setShadow(widgetTheme.getTextShadow()); + renderer.setAlignment(Alignment.CenterLeft, width, height); + renderer.setScale(1f); + renderer.setPos(x, y); + renderer.draw(key.getFormatted()); + } else { + drawable.draw(context, x, y, width, height, widgetTheme); + } } } } diff --git a/src/main/java/gregtech/common/metatileentities/multi/MetaTileEntityLargeBoiler.java b/src/main/java/gregtech/common/metatileentities/multi/MetaTileEntityLargeBoiler.java index 935c04ef6ee..6cab3547ebc 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/MetaTileEntityLargeBoiler.java +++ b/src/main/java/gregtech/common/metatileentities/multi/MetaTileEntityLargeBoiler.java @@ -39,11 +39,11 @@ import codechicken.lib.render.pipeline.IVertexOperation; import codechicken.lib.vec.Matrix4; import com.cleanroommc.modularui.api.GuiAxis; -import com.cleanroommc.modularui.api.drawable.IDrawable; import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.api.widget.Interactable; import com.cleanroommc.modularui.drawable.ItemDrawable; import com.cleanroommc.modularui.drawable.Rectangle; +import com.cleanroommc.modularui.drawable.text.RichText; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.utils.Color; import com.cleanroommc.modularui.value.sync.BooleanSyncValue; @@ -219,27 +219,27 @@ protected MultiblockUIFactory createUIFactory() { }); } - private void addCustomData(List keyList) { + private void addCustomData(RichText keyList) { if (isStructureFormed()) { // Steam Output line IKey steamOutput = KeyUtil.number(TextFormatting.AQUA, recipeLogic::getLastTickSteam, " L/t"); - keyList.add(KeyUtil.lang(TextFormatting.GRAY, + keyList.addLine(KeyUtil.lang(TextFormatting.GRAY, "gregtech.multiblock.large_boiler.steam_output", steamOutput)); // Efficiency line IKey efficiency = KeyUtil.number( () -> getNumberColor(recipeLogic.getHeatScaled()), recipeLogic::getHeatScaled, "%"); - keyList.add(KeyUtil.lang(TextFormatting.GRAY, + keyList.addLine(KeyUtil.lang(TextFormatting.GRAY, "gregtech.multiblock.large_boiler.efficiency", efficiency)); // Throttle line IKey throttle = KeyUtil.number( () -> getNumberColor(getThrottle()), this::getThrottle, "%"); - keyList.add(KeyUtil.lang(TextFormatting.GRAY, + keyList.addLine(KeyUtil.lang(TextFormatting.GRAY, "gregtech.multiblock.large_boiler.throttle", throttle)); } } diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java index 34fd1aecd32..bb8239d8723 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/MetaTileEntityElectricBlastFurnace.java @@ -47,7 +47,7 @@ import net.minecraftforge.fml.relauncher.Side; import net.minecraftforge.fml.relauncher.SideOnly; -import com.cleanroommc.modularui.api.drawable.IDrawable; +import com.cleanroommc.modularui.drawable.text.RichText; import com.cleanroommc.modularui.value.sync.DoubleSyncValue; import com.cleanroommc.modularui.value.sync.IntSyncValue; import org.jetbrains.annotations.NotNull; @@ -119,13 +119,13 @@ protected MultiblockUIFactory createUIFactory() { .addProgressLine(progress::getDoubleValue)); } - private Consumer> addHeatCapacity(IntSyncValue temp) { + private Consumer addHeatCapacity(IntSyncValue temp) { return keyList -> { if (isStructureFormed()) { var heatString = KeyUtil.number(TextFormatting.RED, temp::getIntValue, "K"); - keyList.add(KeyUtil.lang(TextFormatting.GRAY, + keyList.addLine(KeyUtil.lang(TextFormatting.GRAY, "gregtech.multiblock.blast_furnace.max_temperature", heatString)); } }; diff --git a/src/main/java/gregtech/common/metatileentities/multi/electric/generator/MetaTileEntityLargeTurbine.java b/src/main/java/gregtech/common/metatileentities/multi/electric/generator/MetaTileEntityLargeTurbine.java index c16d82020d8..a49c787c388 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/electric/generator/MetaTileEntityLargeTurbine.java +++ b/src/main/java/gregtech/common/metatileentities/multi/electric/generator/MetaTileEntityLargeTurbine.java @@ -11,7 +11,6 @@ import gregtech.api.metatileentity.multiblock.ui.MultiblockUIFactory; import gregtech.api.mui.GTGuiTextures; import gregtech.api.mui.sync.FixedIntArraySyncValue; -import gregtech.api.mui.widget.GregtechDisplayScreen; import gregtech.api.pattern.BlockPattern; import gregtech.api.pattern.FactoryBlockPattern; import gregtech.api.pattern.PatternMatchContext; @@ -208,22 +207,40 @@ protected MultiblockUIFactory createUIFactory() { .syncValue("dura", rotorFree) .syncValue("fuel_amount", fuelAmount) .syncValue("prev_duration", prevDuration) - .customScreen(() -> new GregtechDisplayScreen(this) - .padding(4) - .energy(this::getMaxVoltage, recipeLogic::getRecipeEUt) - .addLine(buffer -> { - buffer.writeBoolean(isStructureFormed()); - if (isStructureFormed()) - buffer.writeInt(noRotor ? -1 : getRotorHolder().getTotalEfficiency()); - }, buffer -> { - if (!buffer.readBoolean()) return null; - int i = buffer.readInt(); - if (i < 0) return null; - return KeyUtil.lang(TextFormatting.GRAY, - "gregtech.multiblock.turbine.efficiency", i); - }) - .fuelNeeded(recipeLogic::getRecipeFluidInputInfo, recipeLogic::getPreviousRecipeDuration) - .status()) + // .customScreen(() -> new ScrollWidget<>(new VerticalScrollData()) + // .padding(4).sizeRel(1f) + // .child(new RichTextWidget() + // .sizeRel(1f) + // .autoUpdate(true) + // .alignment(Alignment.TopLeft) + // .textBuilder(richText -> { + // richText.add(KeyUtil.lang(TextFormatting.WHITE, getMetaFullName())).newLine(); + // + // if (!isStructureFormed()) + // richText.add(KeyUtil.lang(TextFormatting.RED, "gregtech.multiblock.invalid_structure")).newLine(); + // + // long v = getMaxVoltage(); + // String voltageName = GTValues.VOCNF[GTUtility.getFloorTierByVoltage(v)]; + // richText.add(KeyUtil.lang(TextFormatting.GRAY, "gregtech.multiblock.max_energy_per_tick", + // TextFormattingUtil.formatNumbers(v), IKey.str(voltageName).format(TextFormatting.RESET))).newLine(); + // })) + // new GregtechDisplayScreen(this) + // .padding(4) + // .energy(this::getMaxVoltage, recipeLogic::getRecipeEUt) + // .addLine(buffer -> { + // buffer.writeBoolean(isStructureFormed()); + // if (isStructureFormed()) + // buffer.writeInt(noRotor ? -1 : getRotorHolder().getTotalEfficiency()); + // }, buffer -> { + // if (!buffer.readBoolean()) return null; + // int i = buffer.readInt(); + // if (i < 0) return null; + // return KeyUtil.lang(TextFormatting.GRAY, + // "gregtech.multiblock.turbine.efficiency", i); + // }) + // .fuelNeeded(recipeLogic::getRecipeFluidInputInfo, recipeLogic::getPreviousRecipeDuration) + // .status() + // ) .configureDisplayText(builder -> builder .setWorkingStatus(recipeLogic::isWorkingEnabled, recipeLogic::isActive) .addEnergyProductionLine(getMaxVoltage(), recipeLogic.getRecipeEUt())