Skip to content

Commit 55fefcd

Browse files
committed
port to rich text
1 parent 36a9249 commit 55fefcd

File tree

4 files changed

+206
-90
lines changed

4 files changed

+206
-90
lines changed

src/main/java/gregtech/api/metatileentity/multiblock/ui/MultiblockUIFactory.java

Lines changed: 164 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,17 @@
1919
import net.minecraft.util.text.TextFormatting;
2020

2121
import com.cleanroommc.modularui.api.drawable.IDrawable;
22+
import com.cleanroommc.modularui.api.drawable.IHoverable;
2223
import com.cleanroommc.modularui.api.drawable.IKey;
24+
import com.cleanroommc.modularui.api.drawable.IRichTextBuilder;
25+
import com.cleanroommc.modularui.api.widget.ITooltip;
2326
import com.cleanroommc.modularui.api.widget.IWidget;
24-
import com.cleanroommc.modularui.drawable.text.DynamicKey;
27+
import com.cleanroommc.modularui.drawable.text.RichText;
2528
import com.cleanroommc.modularui.factory.PosGuiData;
2629
import com.cleanroommc.modularui.screen.ModularPanel;
30+
import com.cleanroommc.modularui.screen.RichTooltip;
31+
import com.cleanroommc.modularui.screen.viewport.GuiContext;
32+
import com.cleanroommc.modularui.theme.WidgetTheme;
2733
import com.cleanroommc.modularui.utils.Alignment;
2834
import com.cleanroommc.modularui.value.sync.BooleanSyncValue;
2935
import com.cleanroommc.modularui.value.sync.IntSyncValue;
@@ -33,29 +39,30 @@
3339
import com.cleanroommc.modularui.widget.ScrollWidget;
3440
import com.cleanroommc.modularui.widget.Widget;
3541
import com.cleanroommc.modularui.widget.scroll.VerticalScrollData;
42+
import com.cleanroommc.modularui.widget.sizer.Area;
43+
import com.cleanroommc.modularui.widget.sizer.Box;
3644
import com.cleanroommc.modularui.widgets.CycleButtonWidget;
3745
import com.cleanroommc.modularui.widgets.ProgressWidget;
46+
import com.cleanroommc.modularui.widgets.RichTextWidget;
3847
import com.cleanroommc.modularui.widgets.SlotGroupWidget;
39-
import com.cleanroommc.modularui.widgets.layout.Column;
4048
import com.cleanroommc.modularui.widgets.layout.Flow;
41-
import com.cleanroommc.modularui.widgets.layout.Row;
42-
import it.unimi.dsi.fastutil.ints.Int2ObjectArrayMap;
43-
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
4449
import org.jetbrains.annotations.NotNull;
4550
import org.jetbrains.annotations.Nullable;
4651

4752
import java.io.IOException;
4853
import java.util.ArrayList;
4954
import java.util.Collections;
5055
import java.util.List;
56+
import java.util.Objects;
5157
import java.util.function.BiFunction;
5258
import java.util.function.BooleanSupplier;
5359
import java.util.function.Consumer;
5460
import java.util.function.DoubleSupplier;
55-
import java.util.function.Function;
5661
import java.util.function.IntSupplier;
5762
import java.util.function.Supplier;
5863

64+
import static com.cleanroommc.modularui.api.drawable.IKey.renderer;
65+
5966
public class MultiblockUIFactory {
6067

6168
private final MultiblockWithDisplayBase mte;
@@ -144,7 +151,7 @@ private Widget<?> createIndicator() {
144151
.pos(174 - 5, screenHeight - 18 - 3)
145152
.onUpdateListener(w -> w.overlay(getIndicatorOverlay(builder)))
146153
.tooltip(tooltip -> tooltip.setAutoUpdate(true))
147-
.tooltipBuilder(tooltip -> tooltip.addDrawableLines(builder.getTextList()));
154+
.tooltipBuilder(builder::buildTooltip);
148155
}
149156

150157
private IDrawable getIndicatorOverlay(Builder builder) {
@@ -308,27 +315,29 @@ public MultiblockUIFactory customScreen(Supplier<ParentWidget<?>> customScreen)
308315
protected Widget<?> createScreen(PanelSyncManager syncManager) {
309316
final var builder = builder();
310317
this.displayText.accept(builder);
311-
var col = new Column();
312-
builder.build(col);
318+
RichTextWidget widget = new RichTextWidget();
319+
builder.buildDisplay(widget);
313320
final var compare = builder();
314321

315322
return new ParentWidget<>()
316323
.child(createIndicator())
317324
.child(customScreen != null ? customScreen.get() : new ScrollWidget<>(new VerticalScrollData())
318325
.sizeRel(1f)
319-
.child(col.expanded()
326+
.child(widget.sizeRel(1f)
327+
.alignment(Alignment.TopLeft)
320328
.margin(4, 4)
321329
.onUpdateListener(column -> {
322330
// really debating on if the display screen should be its own widget
323-
compare.clear();
331+
// compare.clear();
324332
this.displayText.accept(compare);
325-
if (!builder.hasChanged(compare) && !dirty) return;
326-
builder.clear();
327-
column.getChildren().clear();
328-
this.displayText.accept(builder);
329-
builder.build(column);
330-
resize(column);
331-
dirty = false;
333+
// if (!builder.hasChanged(compare) && !dirty) return;
334+
// builder.clear();
335+
if (builder.hasChanged(compare))
336+
widget.markDirty();
337+
// this.displayText.accept(builder);
338+
// builder.build(column);
339+
// resize(column);
340+
// dirty = false;
332341
})))
333342
.background(GTGuiTextures.DISPLAY)
334343
.size(190, screenHeight)
@@ -465,9 +474,11 @@ protected static Builder builder() {
465474
@SuppressWarnings({ "UnusedReturnValue", "unused" })
466475
public static class Builder {
467476

468-
private final List<IDrawable> textList;
469-
private Function<IDrawable, Widget<?>> widgetFunction = Builder::keyMapper;
470-
private final Int2ObjectMap<IDrawable> tooltips = new Int2ObjectArrayMap<>();
477+
private final RichText text = new RichText();
478+
private final List<Consumer<IRichTextBuilder<? extends IRichTextBuilder<?>>>> textList = new ArrayList<>();
479+
// private final List<IDrawable> textList;
480+
// private Function<IDrawable, Widget<?>> widgetFunction = Builder::keyMapper;
481+
// private final Int2ObjectMap<IDrawable> tooltips = new Int2ObjectArrayMap<>();
471482

472483
private BooleanSupplier isWorkingEnabled = () -> false;
473484
private BooleanSupplier isActive = () -> false;
@@ -479,15 +490,15 @@ public static class Builder {
479490
private IKey runningKey = IKey.lang("gregtech.multiblock.running").format(TextFormatting.GREEN);
480491
private boolean dirty;
481492

482-
protected static Widget<?> keyMapper(IDrawable key) {
483-
return key.asWidget()
484-
.widthRel(1f)
485-
.height(12);
486-
}
493+
// protected static Widget<?> keyMapper(IDrawable key) {
494+
// return key.asWidget()
495+
// .widthRel(1f)
496+
// .height(12);
497+
// }
487498

488-
private Builder() {
489-
this.textList = new ArrayList<>();
490-
}
499+
// private Builder() {
500+
// this.textList = new ArrayList<>();
501+
// }
491502

492503
public Builder structureFormed(boolean structureFormed) {
493504
this.isStructureFormed = structureFormed;
@@ -672,11 +683,11 @@ public Builder addWorkingStatusLine() {
672683

673684
addKey(KeyUtil.string(() -> {
674685
if (!isWorkingEnabled.getAsBoolean()) {
675-
return TextFormatting.GOLD + pausedKey.get();
686+
return pausedKey.getFormatted();
676687
} else if (isActive.getAsBoolean()) {
677-
return TextFormatting.GREEN + runningKey.get();
688+
return runningKey.getFormatted();
678689
} else {
679-
return TextFormatting.GRAY + idlingKey.get();
690+
return idlingKey.getFormatted();
680691
}
681692
}));
682693
return this;
@@ -881,25 +892,25 @@ public Builder addFuelNeededLine(String fuelName, IntSupplier previousRecipeDura
881892

882893
/** Insert an empty line into the text list. */
883894
public Builder addEmptyLine() {
884-
addKey(IKey.EMPTY); // this is going to cause problems maybe
895+
this.text.newLine();
885896
return this;
886897
}
887898

888899
/** Add custom text dynamically, allowing for custom application logic. */
889-
public Builder addCustom(Consumer<List<IDrawable>> customConsumer) {
890-
List<IDrawable> customKeys = new ArrayList<>();
891-
customConsumer.accept(customKeys);
892-
customKeys.forEach(this::addKey);
900+
public Builder addCustom(Consumer<RichText> customConsumer) {
901+
// List<IDrawable> customKeys = new ArrayList<>();
902+
customConsumer.accept(this.text);
903+
// customKeys.forEach(this::addKey);
893904
return this;
894905
}
895906

896-
/**
897-
* @param widgetFunction function to build widgets from keys
898-
*/
899-
public Builder widgetFunction(Function<IDrawable, Widget<?>> widgetFunction) {
900-
this.widgetFunction = widgetFunction;
901-
return this;
902-
}
907+
// /**
908+
// * @param widgetFunction function to build widgets from keys
909+
// */
910+
// public Builder widgetFunction(Function<IDrawable, Widget<?>> widgetFunction) {
911+
// this.widgetFunction = widgetFunction;
912+
// return this;
913+
// }
903914

904915
protected boolean isEmpty() {
905916
return textList.isEmpty();
@@ -909,41 +920,129 @@ protected void clear() {
909920
textList.clear();
910921
}
911922

912-
protected void build(ParentWidget<?> parent) {
913-
for (int i = 0; i < textList.size(); i++) {
914-
var line = this.widgetFunction.apply(textList.get(i));
915-
if (tooltips.containsKey(i))
916-
line.addTooltipLine(tooltips.get(i));
917-
parent.child(line);
918-
}
923+
protected void buildDisplay(RichTextWidget parent) {
924+
parent.textBuilder(richText -> this.textList.forEach(t -> t.accept(richText)));
925+
// for (int i = 0; i < textList.size(); i++) {
926+
// var line = this.widgetFunction.apply(textList.get(i));
927+
// if (tooltips.containsKey(i))
928+
// line.addTooltipLine(tooltips.get(i));
929+
// parent.child(line);
930+
// }
919931
}
920932

921-
protected List<IDrawable> getTextList() {
922-
return Collections.unmodifiableList(textList);
933+
protected void buildTooltip(RichTooltip tooltip) {
934+
this.textList.forEach(t -> t.accept(tooltip));
935+
// parent.tooltipBuilder(richText -> this.textList.forEach(t -> t.accept(richText)));
923936
}
924937

925-
protected boolean hasChanged(Builder other) {
926-
if (textList.size() != other.textList.size()) return true;
927-
for (int i = 0; i < textList.size(); i++) {
928-
IDrawable left = textList.get(i), right = other.textList.get(i);
929-
930-
// dynamic keys are impossible to check, skip
931-
if (left instanceof DynamicKey && right instanceof DynamicKey)
932-
continue;
938+
protected RichText getTextList() {
939+
// return Collections.unmodifiableList(textList);
940+
return this.text;
941+
}
933942

934-
if (!left.equals(right))
943+
protected boolean hasChanged(Builder other) {
944+
List<String> cur = text.getStringRepresentation();
945+
List<String> oth = other.text.getStringRepresentation();
946+
if (cur.size() != oth.size()) return true;
947+
for (int i = 0; i < cur.size(); i++) {
948+
if (!Objects.equals(cur.get(i), oth.get(i)))
935949
return true;
936950
}
937951
return false;
938952
}
939953

940954
private void addKey(IDrawable key) {
941-
this.textList.add(key);
955+
// this.text.add(key);
956+
textList.add(richText -> richText.addLine(key));
957+
// this.textList.add(key);
942958
}
943959

944960
private void addKey(IDrawable key, IDrawable hover) {
945-
this.tooltips.put(textList.size(), hover);
946-
addKey(key);
961+
// this.text.add();
962+
// this.tooltips.put(textList.size(), hover);
963+
// addKey(key.asIcon().asHoverable().addTooltipLine(hover));
964+
addKey(new TestDrawable(key, hover));
965+
}
966+
}
967+
968+
private static class TestDrawable implements IHoverable, ITooltip<TestDrawable> {
969+
970+
private final IDrawable drawable;
971+
private RichTooltip tooltip;
972+
private final Area area;
973+
974+
private TestDrawable(IDrawable drawable, IDrawable hover) {
975+
this.drawable = drawable;
976+
this.area = drawable instanceof IKey key ? calculateArea(key) : new Area();
977+
tooltip().addLine(hover);
978+
}
979+
980+
private Area calculateArea(IKey key) {
981+
renderer.setSimulate(true);
982+
renderer.setScale(1f);
983+
renderer.draw(key.getFormatted());
984+
renderer.getMaxWidth(Collections.singletonList(key.getFormatted()));
985+
int h = (int) renderer.getLastWidth();
986+
int w = (int) renderer.getLastHeight();
987+
renderer.setSimulate(false);
988+
return new Area(0, 0, w, h);
989+
}
990+
991+
@Override
992+
public void setRenderedAt(int x, int y) {
993+
this.area.setPos(x, y);
994+
}
995+
996+
@Override
997+
public Area getRenderedArea() {
998+
return this.area;
999+
}
1000+
1001+
@Override
1002+
public int getWidth() {
1003+
return this.area.w();
1004+
}
1005+
1006+
@Override
1007+
public int getHeight() {
1008+
return this.area.h();
1009+
}
1010+
1011+
@Override
1012+
public Box getMargin() {
1013+
return this.area.getMargin();
1014+
}
1015+
1016+
@Override
1017+
@Nullable
1018+
public RichTooltip getTooltip() {
1019+
return tooltip;
1020+
}
1021+
1022+
@Override
1023+
public @NotNull RichTooltip tooltip() {
1024+
if (this.tooltip == null) this.tooltip = new RichTooltip(area -> area.set(getRenderedArea()));
1025+
return tooltip;
1026+
}
1027+
1028+
@Override
1029+
public TestDrawable tooltip(RichTooltip tooltip) {
1030+
this.tooltip = tooltip;
1031+
return this;
1032+
}
1033+
1034+
@Override
1035+
public void draw(GuiContext context, int x, int y, int width, int height, WidgetTheme widgetTheme) {
1036+
if (drawable instanceof IKey key) {
1037+
renderer.setColor(widgetTheme.getTextColor());
1038+
renderer.setShadow(widgetTheme.getTextShadow());
1039+
renderer.setAlignment(Alignment.CenterLeft, width, height);
1040+
renderer.setScale(1f);
1041+
renderer.setPos(x, y);
1042+
renderer.draw(key.getFormatted());
1043+
} else {
1044+
drawable.draw(context, x, y, width, height, widgetTheme);
1045+
}
9471046
}
9481047
}
9491048
}

src/main/java/gregtech/common/metatileentities/multi/MetaTileEntityLargeBoiler.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,11 @@
3939
import codechicken.lib.render.pipeline.IVertexOperation;
4040
import codechicken.lib.vec.Matrix4;
4141
import com.cleanroommc.modularui.api.GuiAxis;
42-
import com.cleanroommc.modularui.api.drawable.IDrawable;
4342
import com.cleanroommc.modularui.api.drawable.IKey;
4443
import com.cleanroommc.modularui.api.widget.Interactable;
4544
import com.cleanroommc.modularui.drawable.ItemDrawable;
4645
import com.cleanroommc.modularui.drawable.Rectangle;
46+
import com.cleanroommc.modularui.drawable.text.RichText;
4747
import com.cleanroommc.modularui.screen.ModularPanel;
4848
import com.cleanroommc.modularui.utils.Color;
4949
import com.cleanroommc.modularui.value.sync.BooleanSyncValue;
@@ -219,27 +219,27 @@ protected MultiblockUIFactory createUIFactory() {
219219
});
220220
}
221221

222-
private void addCustomData(List<IDrawable> keyList) {
222+
private void addCustomData(RichText keyList) {
223223
if (isStructureFormed()) {
224224
// Steam Output line
225225
IKey steamOutput = KeyUtil.number(TextFormatting.AQUA,
226226
recipeLogic::getLastTickSteam, " L/t");
227227

228-
keyList.add(KeyUtil.lang(TextFormatting.GRAY,
228+
keyList.addLine(KeyUtil.lang(TextFormatting.GRAY,
229229
"gregtech.multiblock.large_boiler.steam_output", steamOutput));
230230

231231
// Efficiency line
232232
IKey efficiency = KeyUtil.number(
233233
() -> getNumberColor(recipeLogic.getHeatScaled()),
234234
recipeLogic::getHeatScaled, "%");
235-
keyList.add(KeyUtil.lang(TextFormatting.GRAY,
235+
keyList.addLine(KeyUtil.lang(TextFormatting.GRAY,
236236
"gregtech.multiblock.large_boiler.efficiency", efficiency));
237237

238238
// Throttle line
239239
IKey throttle = KeyUtil.number(
240240
() -> getNumberColor(getThrottle()),
241241
this::getThrottle, "%");
242-
keyList.add(KeyUtil.lang(TextFormatting.GRAY,
242+
keyList.addLine(KeyUtil.lang(TextFormatting.GRAY,
243243
"gregtech.multiblock.large_boiler.throttle", throttle));
244244
}
245245
}

0 commit comments

Comments
 (0)