Skip to content

Commit de1c8a3

Browse files
committed
1.4.0
improved tooltips `ButtonOption` now consumes itself, so you can access it when building.
1 parent 904e4d6 commit de1c8a3

14 files changed

Lines changed: 104 additions & 130 deletions

File tree

build.gradle.kts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ plugins {
1616
val ciRun = System.getenv().containsKey("GITHUB_ACTIONS")
1717

1818
group = "dev.isxander"
19-
version = "1.3.0"
19+
version = "1.4.0"
2020

2121
if (ciRun)
2222
version = "$version-SNAPSHOT"
@@ -55,11 +55,11 @@ dependencies {
5555
modImplementation("net.fabricmc:fabric-loader:$fabricLoaderVersion")
5656

5757
modImplementation(fabricApi.module("fabric-resource-loader-v0", "0.61.0+1.19.2"))
58-
59-
"testmodImplementation"(sourceSets.main.get().output)
60-
"modTestmodImplementation"("com.terraformersmc:modmenu:4.0.6") {
58+
modImplementation("com.terraformersmc:modmenu:4.0.6") {
6159
exclude(module = "fabric-loader")
6260
}
61+
62+
"testmodImplementation"(sourceSets.main.get().output)
6363
}
6464

6565
java {

changelogs/1.4.0.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
- Improve tooltips a lot:
2+
- They now never get cut off by the edge of the screen
3+
- They never overlap the hovered option/group/category
4+
- They don't take half a second to appear
5+
- They don't disappear when you move your mouse
6+
- `ButtonOption` now consumes itself, so you can access it when building.

src/main/java/dev/isxander/yacl/api/ButtonOption.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,15 @@
99

1010
import java.util.ArrayList;
1111
import java.util.List;
12+
import java.util.function.BiConsumer;
1213
import java.util.function.Consumer;
1314
import java.util.function.Function;
1415

15-
public interface ButtonOption extends Option<Consumer<YACLScreen>> {
16+
public interface ButtonOption extends Option<BiConsumer<YACLScreen, ButtonOption>> {
1617
/**
1718
* Action to be executed upon button press
1819
*/
19-
Consumer<YACLScreen> action();
20+
BiConsumer<YACLScreen, ButtonOption> action();
2021

2122
static Builder createBuilder() {
2223
return new Builder();
@@ -26,8 +27,8 @@ class Builder {
2627
private Text name;
2728
private final List<Text> tooltipLines = new ArrayList<>();
2829
private boolean available = true;
29-
private Function<ButtonOption, Controller<Consumer<YACLScreen>>> controlGetter;
30-
private Consumer<YACLScreen> action;
30+
private Function<ButtonOption, Controller<BiConsumer<YACLScreen, ButtonOption>>> controlGetter;
31+
private BiConsumer<YACLScreen, ButtonOption> action;
3132

3233
private Builder() {
3334

@@ -59,15 +60,23 @@ public Builder tooltip(@NotNull Text... tooltips) {
5960
return this;
6061
}
6162

63+
public Builder action(@NotNull BiConsumer<YACLScreen, ButtonOption> action) {
64+
Validate.notNull(action, "`action` cannot be null");
65+
66+
this.action = action;
67+
return this;
68+
}
69+
6270
/**
6371
* Action to be executed upon button press
6472
*
6573
* @see ButtonOption#action()
6674
*/
75+
@Deprecated
6776
public Builder action(@NotNull Consumer<YACLScreen> action) {
6877
Validate.notNull(action, "`action` cannot be null");
6978

70-
this.action = action;
79+
this.action = (screen, button) -> action.accept(screen);
7180
return this;
7281
}
7382

@@ -87,7 +96,7 @@ public Builder available(boolean available) {
8796
*
8897
* @see dev.isxander.yacl.gui.controllers
8998
*/
90-
public Builder controller(@NotNull Function<ButtonOption, Controller<Consumer<YACLScreen>>> control) {
99+
public Builder controller(@NotNull Function<ButtonOption, Controller<BiConsumer<YACLScreen, ButtonOption>>> control) {
91100
Validate.notNull(control, "`control` cannot be null");
92101

93102
this.controlGetter = control;

src/main/java/dev/isxander/yacl/api/Option.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ public interface Option<T> {
4747
*/
4848
boolean available();
4949

50+
/**
51+
* Sets if the option can be configured after being built
52+
*
53+
* @see Option#available()
54+
*/
55+
void setAvailable(boolean available);
56+
5057
/**
5158
* Class of the option type.
5259
* Used by some controllers.

src/main/java/dev/isxander/yacl/gui/CategoryListWidget.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ public void render(MatrixStack matrices, int index, int y, int x, int entryWidth
8080
}
8181

8282
private void postRender(MatrixStack matrices, int mouseX, int mouseY, float tickDelta) {
83-
categoryButton.renderHoveredTooltip(matrices, mouseX, mouseY);
83+
categoryButton.renderHoveredTooltip(matrices);
8484
}
8585

8686
@Override

src/main/java/dev/isxander/yacl/gui/OptionListWidget.java

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import dev.isxander.yacl.api.Option;
66
import dev.isxander.yacl.api.OptionGroup;
77
import dev.isxander.yacl.api.utils.Dimension;
8-
import dev.isxander.yacl.impl.YACLConstants;
98
import net.minecraft.client.MinecraftClient;
109
import net.minecraft.client.font.MultilineText;
1110
import net.minecraft.client.font.TextRenderer;
@@ -14,10 +13,8 @@
1413
import net.minecraft.client.gui.screen.Screen;
1514
import net.minecraft.client.gui.screen.narration.NarrationMessageBuilder;
1615
import net.minecraft.client.gui.screen.narration.NarrationPart;
17-
import net.minecraft.client.gui.widget.ButtonWidget;
1816
import net.minecraft.client.gui.widget.ElementListWidget;
1917
import net.minecraft.client.util.math.MatrixStack;
20-
import net.minecraft.text.OrderedText;
2118
import net.minecraft.text.Text;
2219
import net.minecraft.util.math.MathHelper;
2320
import org.jetbrains.annotations.Nullable;
@@ -296,25 +293,24 @@ public List<? extends Element> children() {
296293
public class GroupSeparatorEntry extends Entry {
297294
private final OptionGroup group;
298295
private final MultilineText wrappedName;
299-
private final List<OrderedText> wrappedTooltip;
296+
private final MultilineText wrappedTooltip;
300297

301298
private final LowProfileButtonWidget expandMinimizeButton;
302299

303-
private float hoveredTicks = 0;
304-
private int prevMouseX, prevMouseY;
305-
306300
private final Screen screen;
307301
private final TextRenderer textRenderer = MinecraftClient.getInstance().textRenderer;
308302

309303
private boolean groupExpanded;
310304

311305
private List<OptionEntry> optionEntries;
312306

307+
private int y;
308+
313309
private GroupSeparatorEntry(OptionGroup group, Screen screen) {
314310
this.group = group;
315311
this.screen = screen;
316312
this.wrappedName = MultilineText.create(textRenderer, group.name(), getRowWidth() - 45);
317-
this.wrappedTooltip = textRenderer.wrapLines(group.tooltip(), screen.width / 2);
313+
this.wrappedTooltip = MultilineText.create(textRenderer, group.tooltip(), screen.width / 3 * 2);
318314
this.groupExpanded = !group.collapsed();
319315
this.expandMinimizeButton = new LowProfileButtonWidget(0, 0, 20, 20, Text.empty(), btn -> {
320316
setExpanded(!isExpanded());
@@ -324,26 +320,19 @@ private GroupSeparatorEntry(OptionGroup group, Screen screen) {
324320

325321
@Override
326322
public void render(MatrixStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
323+
this.y = y;
324+
327325
expandMinimizeButton.x = x;
328326
expandMinimizeButton.y = y + entryHeight / 2 - expandMinimizeButton.getHeight() / 2;
329327
expandMinimizeButton.render(matrices, mouseX, mouseY, tickDelta);
330328

331-
hovered &= !expandMinimizeButton.isMouseOver(mouseX, mouseY);
332-
if (hovered && (!YACLConstants.HOVER_MOUSE_RESET || (mouseX == prevMouseX && mouseY == prevMouseY)))
333-
hoveredTicks += tickDelta;
334-
else
335-
hoveredTicks = 0;
336-
337329
wrappedName.drawCenterWithShadow(matrices, x + entryWidth / 2, y + getYPadding());
338-
339-
prevMouseX = mouseX;
340-
prevMouseY = mouseY;
341330
}
342331

343332
@Override
344333
public void postRender(MatrixStack matrices, int mouseX, int mouseY, float delta) {
345-
if (hoveredTicks >= YACLConstants.HOVER_TICKS) {
346-
screen.renderOrderedTooltip(matrices, wrappedTooltip, mouseX, mouseY);
334+
if (isHovered() && !expandMinimizeButton.isMouseOver(mouseX, mouseY)) {
335+
YACLScreen.renderMultilineTooltip(matrices, textRenderer, wrappedTooltip, getRowLeft() + getRowWidth() / 2, y - 3, y + getItemHeight() + 3, screen.width, screen.height);
347336
}
348337
}
349338

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,13 @@
11
package dev.isxander.yacl.gui;
22

3-
import dev.isxander.yacl.impl.YACLConstants;
43
import net.minecraft.client.MinecraftClient;
54
import net.minecraft.client.font.MultilineText;
65
import net.minecraft.client.gui.screen.Screen;
76
import net.minecraft.client.gui.widget.ButtonWidget;
87
import net.minecraft.client.util.math.MatrixStack;
9-
import net.minecraft.text.OrderedText;
108
import net.minecraft.text.Text;
119

12-
import java.util.List;
13-
1410
public class TooltipButtonWidget extends ButtonWidget {
15-
protected float hoveredTicks = 0;
16-
protected int prevMouseX, prevMouseY;
1711

1812
protected final Screen screen;
1913
protected MultilineText wrappedDescription;
@@ -24,27 +18,13 @@ public TooltipButtonWidget(Screen screen, int x, int y, int width, int height, T
2418
setTooltip(tooltip);
2519
}
2620

27-
@Override
28-
public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
29-
super.render(matrices, mouseX, mouseY, delta);
30-
31-
if (isHovered() && (!YACLConstants.HOVER_MOUSE_RESET || (prevMouseX == mouseX && prevMouseY == mouseY))) {
32-
hoveredTicks += delta;
33-
} else {
34-
hoveredTicks = 0;
35-
}
36-
37-
prevMouseX = mouseX;
38-
prevMouseY = mouseY;
39-
}
40-
41-
public void renderHoveredTooltip(MatrixStack matrices, int mouseX, int mouseY) {
42-
if (hoveredTicks >= YACLConstants.HOVER_TICKS) {
43-
YACLScreen.renderMultilineTooltip(matrices, MinecraftClient.getInstance().textRenderer, wrappedDescription, mouseX, mouseY, screen.width, screen.height);
21+
public void renderHoveredTooltip(MatrixStack matrices) {
22+
if (isHovered()) {
23+
YACLScreen.renderMultilineTooltip(matrices, MinecraftClient.getInstance().textRenderer, wrappedDescription, x + width / 2, y - 4, y + height + 4, screen.width, screen.height);
4424
}
4525
}
4626

4727
public void setTooltip(Text tooltip) {
48-
wrappedDescription = MultilineText.create(MinecraftClient.getInstance().textRenderer, tooltip, screen.width / 2);
28+
wrappedDescription = MultilineText.create(MinecraftClient.getInstance().textRenderer, tooltip, screen.width / 3);
4929
}
5030
}

src/main/java/dev/isxander/yacl/gui/YACLScreen.java

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,17 @@
44
import dev.isxander.yacl.api.*;
55
import dev.isxander.yacl.api.utils.Dimension;
66
import dev.isxander.yacl.api.utils.OptionUtils;
7-
import dev.isxander.yacl.impl.YACLConstants;
87
import net.minecraft.client.font.MultilineText;
98
import net.minecraft.client.font.TextRenderer;
109
import net.minecraft.client.gui.Element;
1110
import net.minecraft.client.gui.screen.Screen;
12-
import net.minecraft.client.gui.tooltip.TooltipComponent;
1311
import net.minecraft.client.render.*;
1412
import net.minecraft.client.util.math.MatrixStack;
1513
import net.minecraft.text.Text;
1614
import net.minecraft.util.Formatting;
1715
import net.minecraft.util.math.Matrix4f;
1816

19-
import java.util.ArrayList;
2017
import java.util.HashSet;
21-
import java.util.List;
2218
import java.util.Set;
2319
import java.util.concurrent.atomic.AtomicBoolean;
2420

@@ -118,7 +114,7 @@ public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) {
118114

119115
for (Element child : children()) {
120116
if (child instanceof TooltipButtonWidget tooltipButtonWidget) {
121-
tooltipButtonWidget.renderHoveredTooltip(matrices, mouseX, mouseY);
117+
tooltipButtonWidget.renderHoveredTooltip(matrices);
122118
}
123119
}
124120
}
@@ -220,21 +216,24 @@ public void close() {
220216
client.setScreen(parent);
221217
}
222218

223-
public static void renderMultilineTooltip(MatrixStack matrices, TextRenderer textRenderer, MultilineText text, int x, int y, int screenWidth, int screenHeight) {
219+
public static void renderMultilineTooltip(MatrixStack matrices, TextRenderer textRenderer, MultilineText text, int centerX, int yAbove, int yBelow, int screenWidth, int screenHeight) {
224220
if (text.count() > 0) {
225221
int maxWidth = text.getMaxWidth();
226222
int lineHeight = textRenderer.fontHeight + 1;
227223
int height = text.count() * lineHeight - 1;
228224

225+
int belowY = yBelow + 12;
226+
int aboveY = yAbove - height + 12;
227+
int maxBelow = screenHeight - (belowY + height);
228+
int minAbove = aboveY - height;
229+
int y = belowY;
230+
if (maxBelow < -8)
231+
y = maxBelow > minAbove ? belowY : aboveY;
232+
233+
int x = centerX - text.getMaxWidth() / 2 - 12;
234+
229235
int drawX = x + 12;
230236
int drawY = y - 12;
231-
if (drawX + maxWidth > screenWidth) {
232-
drawX -= 28 + maxWidth;
233-
}
234-
235-
if (drawY + height + 6 > screenHeight) {
236-
drawY = screenHeight - height - 6;
237-
}
238237

239238
matrices.push();
240239
Tessellator tessellator = Tessellator.getInstance();

src/main/java/dev/isxander/yacl/gui/controllers/ActionController.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
import org.jetbrains.annotations.ApiStatus;
1010
import org.lwjgl.glfw.GLFW;
1111

12-
import java.util.function.Consumer;
12+
import java.util.function.BiConsumer;
1313

1414
/**
1515
* Simple controller that simply runs the button action on press
1616
* and renders a {@link} Text on the right.
1717
*/
18-
public class ActionController implements Controller<Consumer<YACLScreen>> {
18+
public class ActionController implements Controller<BiConsumer<YACLScreen, ButtonOption>> {
1919
public static final Text DEFAULT_TEXT = Text.translatable("yacl.control.action.execute");
2020

2121
private final ButtonOption option;
@@ -75,7 +75,7 @@ public ActionControllerElement(ActionController control, YACLScreen screen, Dime
7575

7676
public void executeAction() {
7777
playDownSound();
78-
control.option().action().accept(screen);
78+
control.option().action().accept(screen, control.option());
7979
}
8080

8181
@Override

0 commit comments

Comments
 (0)