Skip to content

Commit 30e6cb8

Browse files
authored
Dev/gui improvements (#455)
* A bunch of modular GUI fixes / improvements. Fixed some issues with GuiContextMenu Fixed GuiText depth not accounting for underline's additional z offset. Fixed slot overlay rendering. Fixed GuiEntityRenderer. Added filtering to GuiList. Support line breaks in tooltip translations. Made some improvements to text field suggestions. * Fixed "Between" constraint and ModularSlot place item validation. * Added a little more functionality to GuiSlots * Move JEI compat to internal package and added JEI runtime dep.
1 parent c59e0a7 commit 30e6cb8

18 files changed

+409
-120
lines changed

Diff for: build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ dependencies {
8585

8686
compileOnly(fg.deobf("mezz.jei:jei-${mc_version}-common-api:${jei_version}"))
8787
compileOnly(fg.deobf("mezz.jei:jei-${mc_version}-forge-api:${jei_version}"))
88+
runtimeOnly(fg.deobf("mezz.jei:jei-${mc_version}-forge:${jei_version}"))
8889
}
8990

9091
test {

Diff for: src/main/java/codechicken/lib/compat/JEIPlugin.java

-37
This file was deleted.

Diff for: src/main/java/codechicken/lib/gui/modular/ModularGui.java

+16-23
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,15 @@
1515
import net.minecraft.network.chat.Component;
1616
import net.minecraft.resources.ResourceLocation;
1717
import net.minecraft.world.inventory.Slot;
18+
import net.minecraft.world.item.ItemStack;
1819
import org.apache.logging.log4j.LogManager;
1920
import org.apache.logging.log4j.Logger;
2021
import org.apache.logging.log4j.util.TriConsumer;
2122
import org.jetbrains.annotations.NotNull;
2223
import org.jetbrains.annotations.Nullable;
2324

24-
import java.util.ArrayList;
25-
import java.util.HashMap;
26-
import java.util.List;
27-
import java.util.Map;
25+
import java.util.*;
2826
import java.util.function.Consumer;
29-
import java.util.stream.Stream;
3027

3128
/**
3229
* The modular gui system is built around "Gui Elements" but those elements need to be rendered by a base parent element. That's what this class is.
@@ -68,7 +65,7 @@ public class ModularGui implements GuiParent<ModularGui> {
6865
private final List<TriConsumer<Integer, Integer, Integer>> preKeyPressListeners = new ArrayList<>();
6966
private final List<TriConsumer<Integer, Integer, Integer>> postKeyPressListeners = new ArrayList<>();
7067

71-
private final List<GuiElement<?>> jeiExclusions = new ArrayList<>();
68+
private int jeiHighlightTime = 0;
7269

7370
/**
7471
* @param provider The gui builder that will be used to construct this modular gui when the screen is initialized.
@@ -208,6 +205,7 @@ public boolean vanillaSlotRendering() {
208205
* @param buffers BufferSource can be retried from {@link GuiGraphics}
209206
* @return A new {@link GuiRender} for the current render call.
210207
*/
208+
@Deprecated //If you have the GuiGraphics, use GuiRender#convert to ensure the underlying PoseStack is carried over. That will ensure things like the JEI overlay will be rendered at a
211209
public GuiRender createRender(MultiBufferSource.BufferSource buffers) {
212210
return new GuiRender(mc, buffers);
213211
}
@@ -216,7 +214,7 @@ public GuiRender createRender(MultiBufferSource.BufferSource buffers) {
216214
* Primary render method for ModularGui. The screen implementing ModularGui must call this in its render method.
217215
* Followed by the {@link #renderOverlay(GuiRender, float)} method to handle overlay rendering.
218216
*
219-
* @param render A new gui render call should be constructed for each frame via {@link #createRender(MultiBufferSource.BufferSource)}
217+
* @param render GuiRender instance converted from Minecraft's {@link GuiGraphics} via {@link GuiRender#convert(GuiGraphics)}
220218
*/
221219
public void render(GuiRender render, float partialTicks) {
222220
root.clearGeometryCache();
@@ -260,6 +258,7 @@ public void tick() {
260258
tickListeners.forEach(Runnable::run);
261259
root.tick(mouseX, mouseY);
262260
CursorHelper.setCursor(newCursor);
261+
if (jeiHighlightTime > 0) jeiHighlightTime--;
263262
}
264263

265264
/**
@@ -524,26 +523,20 @@ public void setCursor(ResourceLocation cursor) {
524523
this.newCursor = cursor;
525524
}
526525

527-
/**
528-
* Add an element to the list of jei exclusions.
529-
* Use this for any elements that render outside the normal gui bounds.
530-
* This will ensure JEI does not try to render on top of these elements.
531-
*/
532-
public void jeiExclude(GuiElement<?> element) {
533-
if (!jeiExclusions.contains(element)) {
534-
jeiExclusions.add(element);
535-
}
526+
public List<GuiElement<?>> getJeiExclusions() {
527+
return root.addJeiExclusions(new ArrayList<>());
536528
}
537529

538-
/**
539-
* Remove an element from the list of jei exclusions.
540-
*/
541-
public void removeJEIExclude(GuiElement<?> element) {
542-
jeiExclusions.remove(element);
530+
public List<GuiElement<?>> getJeiDropTargets() {
531+
return root.addJeiDropTargets(new ArrayList<>());
532+
}
533+
534+
public void setJeiHighlightTime(int jeiHighlightTime) {
535+
this.jeiHighlightTime = jeiHighlightTime;
543536
}
544537

545-
public FastStream<GuiElement<?>> getJeiExclusions() {
546-
return FastStream.of(jeiExclusions).filter(GuiElement::isEnabled);
538+
public int getJeiHighlightTime() {
539+
return jeiHighlightTime;
547540
}
548541

549542
/**

Diff for: src/main/java/codechicken/lib/gui/modular/ModularGuiContainer.java

+24-3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@
2929
public class ModularGuiContainer<T extends AbstractContainerMenu> extends AbstractContainerScreen<T> implements ContainerScreenAccess<T> {
3030

3131
public final ModularGui modularGui;
32+
/**
33+
* Flag used to disable vanilla slot highlight rendering.
34+
* */
35+
private boolean renderingSlots = false;
3236

3337
public ModularGuiContainer(T containerMenu, Inventory inventory, ContainerGuiProvider<T> provider) {
3438
super(containerMenu, inventory, Component.empty());
@@ -74,7 +78,7 @@ public void render(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float
7478
if (modularGui.renderBackground()) {
7579
renderBackground(graphics);
7680
}
77-
GuiRender render = modularGui.createRender(graphics.bufferSource());
81+
GuiRender render = GuiRender.convert(graphics);//modularGui.createRender(graphics.bufferSource());
7882
modularGui.render(render, partialTicks);
7983

8084
super.render(graphics, mouseX, mouseY, partialTicks);
@@ -125,7 +129,7 @@ protected boolean handleFloatingItemRender(GuiRender render, int mouseX, int mou
125129
protected boolean renderHoveredStackToolTip(GuiRender guiGraphics, int mouseX, int mouseY) {
126130
if (this.menu.getCarried().isEmpty() && this.hoveredSlot != null && this.hoveredSlot.hasItem()) {
127131
GuiElement<?> handler = modularGui.getSlotHandler(hoveredSlot);
128-
if (handler != null && handler.blockMouseOver(handler, mouseX, mouseY)) {
132+
if (handler != null && (handler.blockMouseOver(handler, mouseX, mouseY) || !handler.isMouseOver())) {
129133
return false;
130134
}
131135
ItemStack itemStack = this.hoveredSlot.getItem();
@@ -191,7 +195,11 @@ protected void renderBg(GuiGraphics guiGraphics, float f, int i, int j) {
191195

192196
@Override
193197
public void renderSlot(GuiGraphics guiGraphics, Slot slot) {
194-
if (modularGui.vanillaSlotRendering()) super.renderSlot(guiGraphics, slot);
198+
if (modularGui.vanillaSlotRendering()) {
199+
super.renderSlot(guiGraphics, slot);
200+
} else {
201+
renderingSlots = true;
202+
}
195203
}
196204

197205
//Modular gui friendly version of the slot render
@@ -240,8 +248,21 @@ public void renderSlot(GuiRender render, Slot slot) {
240248
}
241249
}
242250

251+
@Override
252+
public boolean isHovering(Slot pSlot, double pMouseX, double pMouseY) {
253+
boolean ret = super.isHovering(pSlot, pMouseX, pMouseY);
254+
//Override the isHovering check before renderSlotHighlight is called.
255+
if (ret && renderingSlots && pSlot.isActive()) {
256+
//This breaks the default hoveredSlot assignment, so we need to handle that here.
257+
hoveredSlot = pSlot;
258+
return false;
259+
}
260+
return ret;
261+
}
262+
243263
@Override //Disable vanilla title and inventory name rendering
244264
protected void renderLabels(GuiGraphics guiGraphics, int i, int j) {
265+
renderingSlots = false;
245266
}
246267

247268
@Override

Diff for: src/main/java/codechicken/lib/gui/modular/ModularGuiScreen.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public void render(@NotNull GuiGraphics graphics, int mouseX, int mouseY, float
6767
if (modularGui.renderBackground()) {
6868
renderBackground(graphics);
6969
}
70-
GuiRender render = modularGui.createRender(graphics.bufferSource());
70+
GuiRender render = GuiRender.convert(graphics);
7171
modularGui.render(render, partialTicks);
7272
modularGui.renderOverlay(render, partialTicks);
7373
}

Diff for: src/main/java/codechicken/lib/gui/modular/elements/GuiContextMenu.java

+40-11
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,9 @@
33
import codechicken.lib.gui.modular.ModularGui;
44
import codechicken.lib.gui.modular.lib.Constraints;
55
import codechicken.lib.gui.modular.lib.geometry.GuiParent;
6-
import net.covers1624.quack.collection.FastStream;
76
import net.minecraft.network.chat.Component;
87

9-
import java.util.ArrayList;
10-
import java.util.HashMap;
11-
import java.util.List;
12-
import java.util.Map;
8+
import java.util.*;
139
import java.util.function.BiFunction;
1410
import java.util.function.Supplier;
1511

@@ -26,14 +22,17 @@
2622
public class GuiContextMenu extends GuiElement<GuiContextMenu> {
2723

2824
private BiFunction<GuiContextMenu, Supplier<Component>, GuiButton> buttonBuilder = (menu, label) -> GuiButton.flatColourButton(menu, label, hover -> hover ? 0xFF475b6a : 0xFF151515).constrain(HEIGHT, literal(12));
29-
private final Map<Supplier<Component>, Runnable> options = new HashMap<>();
25+
private final Map<Supplier<Component>, Runnable> options = new LinkedHashMap<>();
3026
private final Map<Supplier<Component>, Supplier<List<Component>>> tooltips = new HashMap<>();
3127
private final List<GuiButton> buttons = new ArrayList<>();
3228
private boolean closeOnItemClicked = true;
3329
private boolean closeOnOutsideClick = true;
30+
private boolean actionOnClick = false;
3431

3532
public GuiContextMenu(ModularGui gui) {
3633
super(gui.getRoot());
34+
jeiExclude();
35+
setOpaque(true);
3736
}
3837

3938
public static GuiContextMenu tooltipStyleMenu(GuiParent<?> parent) {
@@ -52,6 +51,16 @@ public GuiContextMenu setCloseOnOutsideClick(boolean closeOnOutsideClick) {
5251
return this;
5352
}
5453

54+
/**
55+
* By default, the option action fires on mouse button release (like pretty much any UI button in existence)
56+
* Calling this will change that to action on mouse button press, (What minecraft uses for its buttons)
57+
*/
58+
public GuiContextMenu actionOnClick() {
59+
this.actionOnClick = true;
60+
rebuildButtons();
61+
return this;
62+
}
63+
5564
/**
5665
* Only height should be constrained, with will be set automatically to accommodate the provided label.
5766
*/
@@ -87,16 +96,20 @@ private void rebuildButtons() {
8796

8897
//Menu options can be dynamic so the width constraint needs to be dynamic.
8998
//This is probably a little expensive, but its only while a context menu is open.
90-
constrain(WIDTH, dynamic(() -> FastStream.of(options.keySet()).map(Supplier::get).intSum(font()::width) + 6D + 4D));
99+
constrain(WIDTH, dynamic(() -> options.keySet().stream().mapToInt(e -> font().width(e.get())).max().orElse(0) + 6D + 4D));
91100

92101
double height = 3;
93102
for (Supplier<Component> label : options.keySet()) {
94103
Runnable action = options.get(label);
95104
GuiButton button = buttonBuilder.apply(this, label)
96-
.onPress(action)
97105
.constrain(TOP, relative(get(TOP), height))
98106
.constrain(LEFT, relative(get(LEFT), 3))
99107
.constrain(RIGHT, relative(get(RIGHT), -3));
108+
if (actionOnClick) {
109+
button.onClick(action);
110+
} else {
111+
button.onPress(action);
112+
}
100113
if (tooltips.containsKey(label)) {
101114
button.setTooltip(tooltips.get(label));
102115
}
@@ -111,10 +124,12 @@ private void rebuildButtons() {
111124
public boolean mouseClicked(double mouseX, double mouseY, int button, boolean consumed) {
112125
consumed = super.mouseClicked(mouseX, mouseY, button, consumed);
113126
if (isMouseOver() || consumed) {
114-
if (consumed && closeOnItemClicked) {
115-
close();
127+
if (actionOnClick) {
128+
if (consumed && closeOnItemClicked) {
129+
close();
130+
}
131+
return true;
116132
}
117-
return true;
118133
} else if (closeOnOutsideClick) {
119134
close();
120135
return true;
@@ -123,6 +138,20 @@ public boolean mouseClicked(double mouseX, double mouseY, int button, boolean co
123138
return consumed;
124139
}
125140

141+
@Override
142+
public boolean mouseReleased(double mouseX, double mouseY, int button, boolean consumed) {
143+
consumed = super.mouseReleased(mouseX, mouseY, button, consumed);
144+
if (isMouseOver() || consumed) {
145+
if (!actionOnClick) {
146+
if (consumed && closeOnItemClicked) {
147+
close();
148+
}
149+
return true;
150+
}
151+
}
152+
return consumed;
153+
}
154+
126155
public void close() {
127156
getParent().removeChild(this);
128157
}

0 commit comments

Comments
 (0)