diff options
Diffstat (limited to 'src/main')
49 files changed, 1058 insertions, 1034 deletions
diff --git a/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java b/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java index ce0dd4b..fae723e 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/SyncedGuiDescription.java @@ -26,7 +26,7 @@ import net.minecraft.server.world.ServerWorld; import net.minecraft.world.World; import io.github.cottonmc.cotton.gui.client.BackgroundPainter; -import io.github.cottonmc.cotton.gui.client.LibGuiClient; +import io.github.cottonmc.cotton.gui.client.LibGui; import io.github.cottonmc.cotton.gui.networking.NetworkSide; import io.github.cottonmc.cotton.gui.widget.WGridPanel; import io.github.cottonmc.cotton.gui.widget.WLabel; @@ -80,7 +80,7 @@ public class SyncedGuiDescription extends ScreenHandler implements GuiDescriptio } public int getTitleColor() { - return (world.isClient && LibGuiClient.config.darkMode) ? darkTitleColor : titleColor; + return (world.isClient && LibGui.isDarkMode()) ? darkTitleColor : titleColor; } public SyncedGuiDescription setRootPanel(WPanel panel) { @@ -164,7 +164,7 @@ public class SyncedGuiDescription extends ScreenHandler implements GuiDescriptio /** WILL MODIFY toInsert! Returns true if anything was inserted. */ private boolean insertIntoExisting(ItemStack toInsert, Slot slot, PlayerEntity player) { ItemStack curSlotStack = slot.getStack(); - if (!curSlotStack.isEmpty() && canStacksCombine(toInsert, curSlotStack) && slot.canInsert(toInsert)) { + if (!curSlotStack.isEmpty() && ItemStack.canCombine(toInsert, curSlotStack) && slot.canInsert(toInsert)) { int combinedAmount = curSlotStack.getCount() + toInsert.getCount(); int maxAmount = Math.min(toInsert.getMaxCount(), slot.getMaxItemCount()); if (combinedAmount <= maxAmount) { @@ -299,52 +299,6 @@ public class SyncedGuiDescription extends ScreenHandler implements GuiDescriptio } @Nullable - public WWidget doMouseUp(int x, int y, int state) { - if (rootPanel!=null) return rootPanel.onMouseUp(x, y, state); - return null; - } - - @Nullable - public WWidget doMouseDown(int x, int y, int button) { - if (rootPanel!=null) return rootPanel.onMouseDown(x, y, button); - return null; - } - - public void doMouseDrag(int x, int y, int button, double deltaX, double deltaY) { - if (rootPanel!=null) rootPanel.onMouseDrag(x, y, button, deltaX, deltaY); - } - - public void doClick(int x, int y, int button) { - if (focus!=null) { - int wx = focus.getAbsoluteX(); - int wy = focus.getAbsoluteY(); - - if (x>=wx && x<wx+focus.getWidth() && y>=wy && y<wy+focus.getHeight()) { - //Do nothing, focus will get the click soon - } else { - //Invalidate the component first - WWidget lastFocus = focus; - focus = null; - lastFocus.onFocusLost(); - } - } - - //if (rootPanel!=null) rootPanel.onClick(x, y, button); - } - - public void doCharType(char ch) { - if (focus!=null) focus.onCharTyped(ch); - } - - //public void doKeyPress(int key) { - // if (focus!=null) focus.onKeyPressed(key); - //} - - //public void doKeyRelease(int key) { - // if (focus!=null) focus.onKeyReleased(key); - //} - - @Nullable @Override public PropertyDelegate getPropertyDelegate() { return propertyDelegate; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/BackgroundPainter.java b/src/main/java/io/github/cottonmc/cotton/gui/client/BackgroundPainter.java index f00bf80..13ca534 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/BackgroundPainter.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/BackgroundPainter.java @@ -1,5 +1,6 @@ package io.github.cottonmc.cotton.gui.client; +import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.Identifier; import io.github.cottonmc.cotton.gui.widget.WItemSlot; @@ -13,11 +14,12 @@ import io.github.cottonmc.cotton.gui.widget.WWidget; public interface BackgroundPainter { /** * Paint the specified panel to the screen. + * @param matrices The rendering matrix stack * @param left The absolute position of the left of the panel, in gui-screen coordinates * @param top The absolute position of the top of the panel, in gui-screen coordinates * @param panel The panel being painted */ - public void paintBackground(int left, int top, WWidget panel); + public void paintBackground(MatrixStack matrices, int left, int top, WWidget panel); /** * The {@code VANILLA} background painter draws a vanilla-like gui panel using {@linkplain NinePatch nine-patch textures}. @@ -40,9 +42,9 @@ public interface BackgroundPainter { /** * The {@code SLOT} background painter draws item slots or slot-like widgets. */ - public static BackgroundPainter SLOT = (left, top, panel) -> { + public static BackgroundPainter SLOT = (matrices, left, top, panel) -> { if (!(panel instanceof WItemSlot)) { - ScreenDrawing.drawBeveledPanel(left-1, top-1, panel.getWidth()+2, panel.getHeight()+2, 0xB8000000, 0x4C000000, 0xB8FFFFFF); + ScreenDrawing.drawBeveledPanel(matrices, left-1, top-1, panel.getWidth()+2, panel.getHeight()+2, 0xB8000000, 0x4C000000, 0xB8FFFFFF); } else { WItemSlot slot = (WItemSlot)panel; for(int x = 0; x < slot.getWidth()/18; ++x) { @@ -53,26 +55,26 @@ public interface BackgroundPainter { //this will cause a slightly discolored bottom border on vanilla backgrounds but it's necessary for color support, it shouldn't be *too* visible unless you're looking for it int hi = 0xB8FFFFFF; if (slot.isBigSlot()) { - ScreenDrawing.drawBeveledPanel((x * 18) + left - 4, (y * 18) + top - 4, 26, 26, + ScreenDrawing.drawBeveledPanel(matrices, (x * 18) + left - 4, (y * 18) + top - 4, 26, 26, lo, bg, hi); if (slot.getFocusedSlot() == index) { int sx = (x * 18) + left - 4; int sy = (y * 18) + top - 4; - ScreenDrawing.coloredRect(sx, sy, 26, 1, 0xFF_FFFFA0); - ScreenDrawing.coloredRect(sx, sy + 1, 1, 26 - 1, 0xFF_FFFFA0); - ScreenDrawing.coloredRect(sx + 26 - 1, sy + 1, 1, 26 - 1, 0xFF_FFFFA0); - ScreenDrawing.coloredRect(sx + 1, sy + 26 - 1, 26 - 1, 1, 0xFF_FFFFA0); + ScreenDrawing.coloredRect(matrices, sx, sy, 26, 1, 0xFF_FFFFA0); + ScreenDrawing.coloredRect(matrices, sx, sy + 1, 1, 26 - 1, 0xFF_FFFFA0); + ScreenDrawing.coloredRect(matrices, sx + 26 - 1, sy + 1, 1, 26 - 1, 0xFF_FFFFA0); + ScreenDrawing.coloredRect(matrices, sx + 1, sy + 26 - 1, 26 - 1, 1, 0xFF_FFFFA0); } } else { - ScreenDrawing.drawBeveledPanel((x * 18) + left, (y * 18) + top, 16+2, 16+2, + ScreenDrawing.drawBeveledPanel(matrices, (x * 18) + left, (y * 18) + top, 16+2, 16+2, lo, bg, hi); if (slot.getFocusedSlot() == index) { int sx = (x * 18) + left; int sy = (y * 18) + top; - ScreenDrawing.coloredRect(sx, sy, 18, 1, 0xFF_FFFFA0); - ScreenDrawing.coloredRect(sx, sy + 1, 1, 18 - 1, 0xFF_FFFFA0); - ScreenDrawing.coloredRect(sx + 18 - 1, sy + 1, 1, 18 - 1, 0xFF_FFFFA0); - ScreenDrawing.coloredRect(sx + 1, sy + 18 - 1, 18 - 1, 1, 0xFF_FFFFA0); + ScreenDrawing.coloredRect(matrices, sx, sy, 18, 1, 0xFF_FFFFA0); + ScreenDrawing.coloredRect(matrices, sx, sy + 1, 1, 18 - 1, 0xFF_FFFFA0); + ScreenDrawing.coloredRect(matrices, sx + 18 - 1, sy + 1, 1, 18 - 1, 0xFF_FFFFA0); + ScreenDrawing.coloredRect(matrices, sx + 1, sy + 18 - 1, 18 - 1, 1, 0xFF_FFFFA0); } } } @@ -85,11 +87,11 @@ public interface BackgroundPainter { * * @param panelColor the panel background color * @return a colorful gui panel painter - * @see ScreenDrawing#drawGuiPanel(int, int, int, int, int) + * @see ScreenDrawing#drawGuiPanel(MatrixStack, int, int, int, int, int) */ public static BackgroundPainter createColorful(int panelColor) { - return (left, top, panel) -> { - ScreenDrawing.drawGuiPanel(left-8, top-8, panel.getWidth()+16, panel.getHeight()+16, panelColor); + return (matrices, left, top, panel) -> { + ScreenDrawing.drawGuiPanel(matrices, left-8, top-8, panel.getWidth()+16, panel.getHeight()+16, panelColor); }; } @@ -101,11 +103,11 @@ public interface BackgroundPainter { * @return a colorful gui panel painter */ public static BackgroundPainter createColorful(int panelColor, float contrast) { - return (left, top, panel) -> { + return (matrices, left, top, panel) -> { int shadowColor = ScreenDrawing.multiplyColor(panelColor, 1.0f - contrast); int hilightColor = ScreenDrawing.multiplyColor(panelColor, 1.0f + contrast); - ScreenDrawing.drawGuiPanel(left-8, top-8, panel.getWidth()+16, panel.getHeight()+16, shadowColor, panelColor, hilightColor, 0xFF000000); + ScreenDrawing.drawGuiPanel(matrices, left-8, top-8, panel.getWidth()+16, panel.getHeight()+16, shadowColor, panelColor, hilightColor, 0xFF000000); }; } @@ -146,9 +148,9 @@ public interface BackgroundPainter { * @since 1.5.0 */ public static BackgroundPainter createLightDarkVariants(BackgroundPainter light, BackgroundPainter dark) { - return (left, top, panel) -> { - if (LibGuiClient.config.darkMode) dark.paintBackground(left, top, panel); - else light.paintBackground(left, top, panel); + return (matrices, left, top, panel) -> { + if (LibGui.isDarkMode()) dark.paintBackground(matrices, left, top, panel); + else light.paintBackground(matrices, left, top, panel); }; } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java index 055262e..cdb65af 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonClientScreen.java @@ -7,11 +7,14 @@ import net.minecraft.text.Style; import net.minecraft.text.Text; import io.github.cottonmc.cotton.gui.GuiDescription; +import io.github.cottonmc.cotton.gui.impl.CottonScreenImpl; +import io.github.cottonmc.cotton.gui.impl.MouseInputHandler; import io.github.cottonmc.cotton.gui.widget.WPanel; import io.github.cottonmc.cotton.gui.widget.WWidget; +import org.jetbrains.annotations.Nullable; import org.lwjgl.opengl.GL11; -public class CottonClientScreen extends Screen implements TextHoverRendererScreen { +public class CottonClientScreen extends Screen implements CottonScreenImpl { protected GuiDescription description; protected int left = 0; protected int top = 0; @@ -63,6 +66,17 @@ public class CottonClientScreen extends Screen implements TextHoverRendererScree this.client.keyboard.setRepeatEvents(false); } + @Nullable + @Override + public WWidget getLastResponder() { + return lastResponder; + } + + @Override + public void setLastResponder(@Nullable WWidget lastResponder) { + this.lastResponder = lastResponder; + } + /** * Repositions the root panel. * @@ -157,68 +171,46 @@ public class CottonClientScreen extends Screen implements TextHoverRendererScree } } - boolean result = super.mouseClicked(mouseX, mouseY, mouseButton); + super.mouseClicked(mouseX, mouseY, mouseButton); int containerX = (int)mouseX-left; int containerY = (int)mouseY-top; - if (containerX<0 || containerY<0 || containerX>=width || containerY>=height) return result; - if (lastResponder==null) { - lastResponder = description.getRootPanel().hit(containerX, containerY); - if (lastResponder!=null) lastResponder.onMouseDown(containerX-lastResponder.getAbsoluteX(), containerY-lastResponder.getAbsoluteY(), mouseButton); - } else { - //This is a drag instead - } - return result; - + if (containerX<0 || containerY<0 || containerX>=width || containerY>=height) return true; + MouseInputHandler.onMouseDown(description, this, containerX, containerY, mouseButton); + + return true; } @Override public boolean mouseReleased(double mouseX, double mouseY, int mouseButton) { if (description.getRootPanel()==null) return super.mouseReleased(mouseX, mouseY, mouseButton); - boolean result = super.mouseReleased(mouseX, mouseY, mouseButton); + super.mouseReleased(mouseX, mouseY, mouseButton); int containerX = (int)mouseX-left; int containerY = (int)mouseY-top; - - if (lastResponder!=null) { - lastResponder.onMouseUp(containerX-lastResponder.getAbsoluteX(), containerY-lastResponder.getAbsoluteY(), mouseButton); - if (containerX>=0 && containerY>=0 && containerX<width && containerY<height) { - lastResponder.onClick(containerX-lastResponder.getAbsoluteX(), containerY-lastResponder.getAbsoluteY(), mouseButton); - } - } else { - description.getRootPanel().onMouseUp(containerX, containerY, mouseButton); - } - - lastResponder = null; - return result; + MouseInputHandler.onMouseUp(description, this, containerX, containerY, mouseButton); + + return true; } @Override public boolean mouseDragged(double mouseX, double mouseY, int mouseButton, double deltaX, double deltaY) { if (description.getRootPanel()==null) return super.mouseDragged(mouseX, mouseY, mouseButton, deltaX, deltaY); - boolean result = super.mouseDragged(mouseX, mouseY, mouseButton, deltaX, deltaY); + super.mouseDragged(mouseX, mouseY, mouseButton, deltaX, deltaY); int containerX = (int)mouseX-left; int containerY = (int)mouseY-top; - - if (lastResponder!=null) { - lastResponder.onMouseDrag(containerX-lastResponder.getAbsoluteX(), containerY-lastResponder.getAbsoluteY(), mouseButton, deltaX, deltaY); - return result; - } else { - if (containerX<0 || containerY<0 || containerX>=width || containerY>=height) return result; - description.getRootPanel().onMouseDrag(containerX, containerY, mouseButton, deltaX, deltaY); - } - return result; + MouseInputHandler.onMouseDrag(description, this, containerX, containerY, mouseButton, deltaX, deltaY); + + return true; } @Override public boolean mouseScrolled(double mouseX, double mouseY, double amount) { if (description.getRootPanel()==null) return super.mouseScrolled(mouseX, mouseY, amount); - WPanel root = description.getRootPanel(); int containerX = (int)mouseX-left; int containerY = (int)mouseY-top; - - WWidget child = root.hit(containerX, containerY); - child.onMouseScroll(containerX - child.getAbsoluteX(), containerY - child.getAbsoluteY(), amount); + MouseInputHandler.onMouseScroll(description, containerX, containerY, amount); + return true; } @@ -226,12 +218,9 @@ public class CottonClientScreen extends Screen implements TextHoverRendererScree public void mouseMoved(double mouseX, double mouseY) { if (description.getRootPanel()==null) return; - WPanel root = description.getRootPanel(); int containerX = (int)mouseX-left; int containerY = (int)mouseY-top; - - WWidget child = root.hit(containerX, containerY); - child.onMouseMove(containerX - child.getAbsoluteX(), containerY - child.getAbsoluteY()); + MouseInputHandler.onMouseMove(description, containerX, containerY); } @Override @@ -262,7 +251,7 @@ public class CottonClientScreen extends Screen implements TextHoverRendererScree //} @Override - public void renderTextHover(MatrixStack matrices, Style textStyle, int x, int y) { + public void renderTextHover(MatrixStack matrices, @Nullable Style textStyle, int x, int y) { renderTextHoverEffect(matrices, textStyle, x, y); } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonHud.java b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonHud.java index 79111d2..f69bb65 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonHud.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonHud.java @@ -6,7 +6,6 @@ import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.minecraft.client.MinecraftClient; import net.minecraft.client.util.Window; -import net.minecraft.client.util.math.MatrixStack; import io.github.cottonmc.cotton.gui.widget.WWidget; @@ -19,27 +18,40 @@ import java.util.Set; * Manages widgets that are painted on the in-game HUD. */ @Environment(EnvType.CLIENT) -public enum CottonHud implements HudRenderCallback { - INSTANCE; // TODO (4.0): Migrate from singleton to static methods +public final class CottonHud { + private CottonHud() {} + + private static final Set<WWidget> widgets = new HashSet<>(); + private static final Map<WWidget, Positioner> positioners = new HashMap<>(); static { - HudRenderCallback.EVENT.register(INSTANCE); + HudRenderCallback.EVENT.register((matrices, tickDelta) -> { + Window window = MinecraftClient.getInstance().getWindow(); + int hudWidth = window.getScaledWidth(); + int hudHeight = window.getScaledHeight(); + for (WWidget widget : widgets) { + Positioner positioner = positioners.get(widget); + if (positioner != null) { + positioner.reposition(widget, hudWidth, hudHeight); + } + + widget.paint(matrices, widget.getX(), widget.getY(), -1, -1); + } + }); + ClientTickEvents.END_CLIENT_TICK.register(client -> { - for (WWidget widget : INSTANCE.widgets) { + for (WWidget widget : widgets) { widget.tick(); } }); } - private final Set<WWidget> widgets = new HashSet<>(); - private final Map<WWidget, Positioner> positioners = new HashMap<>(); - /** * Adds a new widget to the HUD. * * @param widget the widget */ - public void add(WWidget widget) { + public static void add(WWidget widget) { widgets.add(widget); } @@ -51,7 +63,7 @@ public enum CottonHud implements HudRenderCallback { * @param y the y offset * @see Positioner#of documentation about the offsets */ - public void add(WWidget widget, int x, int y) { + public static void add(WWidget widget, int x, int y) { add(widget, Positioner.of(x, y)); } @@ -65,7 +77,7 @@ public enum CottonHud implements HudRenderCallback { * @param height the height of the widget * @see Positioner#of documentation about the offsets */ - public void add(WWidget widget, int x, int y, int width, int height) { + public static void add(WWidget widget, int x, int y, int width, int height) { add(widget, Positioner.of(x, y)); widget.setSize(width, height); } @@ -76,7 +88,7 @@ public enum CottonHud implements HudRenderCallback { * @param widget the widget * @param positioner the positioner */ - public void add(WWidget widget, Positioner positioner) { + public static void add(WWidget widget, Positioner positioner) { widgets.add(widget); setPositioner(widget, positioner); } @@ -89,7 +101,7 @@ public enum CottonHud implements HudRenderCallback { * @param width the width of the widget * @param height the height of the widget */ - public void add(WWidget widget, Positioner positioner, int width, int height) { + public static void add(WWidget widget, Positioner positioner, int width, int height) { widgets.add(widget); widget.setSize(width, height); setPositioner(widget, positioner); @@ -101,7 +113,7 @@ public enum CottonHud implements HudRenderCallback { * @param widget the widget * @param positioner the positioner */ - public void setPositioner(WWidget widget, Positioner positioner) { + public static void setPositioner(WWidget widget, Positioner positioner) { positioners.put(widget, positioner); } @@ -110,25 +122,10 @@ public enum CottonHud implements HudRenderCallback { * * @param widget the widget */ - public void remove(WWidget widget) { + public static void remove(WWidget widget) { widgets.remove(widget); } - @Override - public void onHudRender(MatrixStack matrices, float tickDelta) { - Window window = MinecraftClient.getInstance().getWindow(); - int hudWidth = window.getScaledWidth(); - int hudHeight = window.getScaledHeight(); - for (WWidget widget : widgets) { - Positioner positioner = positioners.get(widget); - if (positioner != null) { - positioner.reposition(widget, hudWidth, hudHeight); - } - - widget.paint(matrices, widget.getX(), widget.getY(), -1, -1); - } - } - /** * Positioners can be used to change the position of a widget based on the window dimensions. */ diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java index 5b36a66..f6c1429 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/CottonInventoryScreen.java @@ -9,8 +9,11 @@ import net.minecraft.text.Style; import net.minecraft.text.Text; import io.github.cottonmc.cotton.gui.SyncedGuiDescription; +import io.github.cottonmc.cotton.gui.impl.CottonScreenImpl; +import io.github.cottonmc.cotton.gui.impl.MouseInputHandler; import io.github.cottonmc.cotton.gui.widget.WPanel; import io.github.cottonmc.cotton.gui.widget.WWidget; +import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; import org.lwjgl.opengl.GL11; @@ -19,7 +22,7 @@ import org.lwjgl.opengl.GL11; * * @param <T> the description type */ -public class CottonInventoryScreen<T extends SyncedGuiDescription> extends HandledScreen<T> implements TextHoverRendererScreen { +public class CottonInventoryScreen<T extends SyncedGuiDescription> extends HandledScreen<T> implements CottonScreenImpl { protected SyncedGuiDescription description; protected WWidget lastResponder = null; @@ -41,7 +44,7 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl * @param title the screen title */ public CottonInventoryScreen(T description, PlayerEntity player, Text title) { - super(description, player.inventory, title); + super(description, player.getInventory(), title); this.description = description; width = 18*9; height = 18*9; @@ -77,6 +80,17 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl this.client.keyboard.setRepeatEvents(false); } + @Nullable + @Override + public WWidget getLastResponder() { + return lastResponder; + } + + @Override + public void setLastResponder(@Nullable WWidget lastResponder) { + this.lastResponder = lastResponder; + } + /** * Clears the heavyweight peers of this screen's GUI description. */ @@ -177,60 +191,40 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl int containerX = (int)mouseX-x; int containerY = (int)mouseY-y; if (containerX<0 || containerY<0 || containerX>=width || containerY>=height) return result; - if (lastResponder==null) { - lastResponder = description.doMouseDown(containerX, containerY, mouseButton); - } else { - //This is a drag instead - } - return result; + MouseInputHandler.onMouseDown(description, this, containerX, containerY, mouseButton); + + return true; } @Override public boolean mouseReleased(double mouseX, double mouseY, int mouseButton) { //Testing shows that STATE IS ACTUALLY BUTTON - boolean result = super.mouseReleased(mouseX, mouseY, mouseButton); + super.mouseReleased(mouseX, mouseY, mouseButton); int containerX = (int)mouseX-x; int containerY = (int)mouseY-y; - - if (lastResponder!=null) { - lastResponder.onMouseUp(containerX-lastResponder.getAbsoluteX(), containerY-lastResponder.getAbsoluteY(), mouseButton); - if (containerX>=0 && containerY>=0 && containerX<width && containerY<height) { - lastResponder.onClick(containerX-lastResponder.getAbsoluteX(), containerY-lastResponder.getAbsoluteY(), mouseButton); - } - } else { - description.doMouseUp(containerX, containerY, mouseButton); - } - - lastResponder = null; - return result; + MouseInputHandler.onMouseUp(description, this, containerX, containerY, mouseButton); + + return true; } @Override public boolean mouseDragged(double mouseX, double mouseY, int mouseButton, double deltaX, double deltaY) { - boolean result = super.mouseDragged(mouseX, mouseY, mouseButton, deltaX, deltaY); + super.mouseDragged(mouseX, mouseY, mouseButton, deltaX, deltaY); int containerX = (int)mouseX-x; int containerY = (int)mouseY-y; - - if (lastResponder!=null) { - lastResponder.onMouseDrag(containerX-lastResponder.getAbsoluteX(), containerY-lastResponder.getAbsoluteY(), mouseButton, deltaX, deltaY); - return result; - } else { - if (containerX<0 || containerY<0 || containerX>=width || containerY>=height) return result; - description.doMouseDrag(containerX, containerY, mouseButton, deltaX, deltaY); - } - return result; + MouseInputHandler.onMouseDrag(description, this, containerX, containerY, mouseButton, deltaX, deltaY); + + return true; } @Override public boolean mouseScrolled(double mouseX, double mouseY, double amount) { if (description.getRootPanel()==null) return super.mouseScrolled(mouseX, mouseY, amount); - - WPanel root = description.getRootPanel(); + int containerX = (int)mouseX-x; int containerY = (int)mouseY-y; - - WWidget child = root.hit(containerX, containerY); - child.onMouseScroll(containerX - child.getAbsoluteX(), containerY - child.getAbsoluteY(), amount); + MouseInputHandler.onMouseScroll(description, containerX, containerY, amount); + return true; } @@ -238,12 +232,9 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl public void mouseMoved(double mouseX, double mouseY) { if (description.getRootPanel()==null) return; - WPanel root = description.getRootPanel(); int containerX = (int)mouseX-x; int containerY = (int)mouseY-y; - - WWidget child = root.hit(containerX, containerY); - child.onMouseMove(containerX - child.getAbsoluteX(), containerY - child.getAbsoluteY()); + MouseInputHandler.onMouseMove(description, containerX, containerY); } @Override @@ -305,7 +296,7 @@ public class CottonInventoryScreen<T extends SyncedGuiDescription> extends Handl } @Override - public void renderTextHover(MatrixStack matrices, Style textStyle, int x, int y) { + public void renderTextHover(MatrixStack matrices, @Nullable Style textStyle, int x, int y) { renderTextHoverEffect(matrices, textStyle, x, y); } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/LibGui.java b/src/main/java/io/github/cottonmc/cotton/gui/client/LibGui.java new file mode 100644 index 0000000..b55c0fe --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/LibGui.java @@ -0,0 +1,20 @@ +package io.github.cottonmc.cotton.gui.client; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; + +import io.github.cottonmc.cotton.gui.impl.client.LibGuiClient; + +/** + * Provides access to global LibGui data such as the dark mode state. + * + * @since 4.0.0 + */ +@Environment(EnvType.CLIENT) +public final class LibGui { + private LibGui() {} + + public static boolean isDarkMode() { + return LibGuiClient.config.darkMode; + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/LightweightGuiDescription.java b/src/main/java/io/github/cottonmc/cotton/gui/client/LightweightGuiDescription.java index 41b8d49..54ae02f 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/LightweightGuiDescription.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/LightweightGuiDescription.java @@ -32,7 +32,7 @@ public class LightweightGuiDescription implements GuiDescription { @Override public int getTitleColor() { - return (LibGuiClient.config.darkMode) ? darkmodeTitleColor : titleColor; + return (LibGui.isDarkMode()) ? darkmodeTitleColor : titleColor; } @Override diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/NinePatch.java b/src/main/java/io/github/cottonmc/cotton/gui/client/NinePatch.java index 9057739..8059b35 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/NinePatch.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/NinePatch.java @@ -2,24 +2,14 @@ package io.github.cottonmc.cotton.gui.client; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; -import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; -import net.minecraft.resource.Resource; -import net.minecraft.resource.ResourceManager; -import net.minecraft.resource.SinglePreparationResourceReloadListener; +import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.Identifier; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.profiler.Profiler; +import io.github.cottonmc.cotton.gui.impl.client.NinePatchInternals; import io.github.cottonmc.cotton.gui.widget.WWidget; import org.jetbrains.annotations.Nullable; -import java.io.InputStream; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Properties; - /** * The nine-patch background painter paints rectangles using a nine-patch texture. * @@ -167,7 +157,7 @@ public class NinePatch implements BackgroundPainter { } @Override - public void paintBackground(int left, int top, WWidget panel) { + public void paintBackground(MatrixStack matrices, int left, int top, WWidget panel) { int width = panel.getWidth() + leftPadding + rightPadding; int height = panel.getHeight() + topPadding + bottomPadding; left = left - leftPadding; @@ -178,12 +168,12 @@ public class NinePatch implements BackgroundPainter { int y2 = top + height - cornerSize; float uv1 = cornerUv; float uv2 = 1.0f - cornerUv; - Mode mode = this.mode != null ? this.mode : MetadataLoader.INSTANCE.getProperties(texture).getMode(); + Mode mode = this.mode != null ? this.mode : NinePatchInternals.MetadataLoader.INSTANCE.getProperties(texture).getMode(); - ScreenDrawing.texturedRect(left, top, cornerSize, cornerSize, texture, 0, 0, uv1, uv1, 0xFF_FFFFFF); - ScreenDrawing.texturedRect(x2, top, cornerSize, cornerSize, texture, uv2, 0, 1, uv1, 0xFF_FFFFFF); - ScreenDrawing.texturedRect(left, y2, cornerSize, cornerSize, texture, 0, uv2, uv1, 1, 0xFF_FFFFFF); - ScreenDrawing.texturedRect(x2, y2, cornerSize, cornerSize, texture, uv2, uv2, 1, 1, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, left, top, cornerSize, cornerSize, texture, 0, 0, uv1, uv1, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, x2, top, cornerSize, cornerSize, texture, uv2, 0, 1, uv1, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, left, y2, cornerSize, cornerSize, texture, 0, uv2, uv1, 1, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, x2, y2, cornerSize, cornerSize, texture, uv2, uv2, 1, 1, 0xFF_FFFFFF); if (mode == Mode.TILING) { int tileSize = (int) (cornerSize / cornerUv - 2 * cornerSize); @@ -196,8 +186,8 @@ public class NinePatch implements BackgroundPainter { int tileWidth = Math.min(widthLeft, tileSize); float uo = (tileSize - tileWidth) * px; // Used to remove unnecessary pixels on the X axis - ScreenDrawing.texturedRect(x1 + i * tileSize, top, tileWidth, cornerSize, texture, uv1, 0, uv2 - uo, uv1, 0xFF_FFFFFF); - ScreenDrawing.texturedRect(x1 + i * tileSize, y2, tileWidth, cornerSize, texture, uv1, uv2, uv2 - uo, 1, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, x1 + i * tileSize, top, tileWidth, cornerSize, texture, uv1, 0, uv2 - uo, uv1, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, x1 + i * tileSize, y2, tileWidth, cornerSize, texture, uv1, uv2, uv2 - uo, 1, 0xFF_FFFFFF); // Reset the height left each time the Y is looped heightLeft = height - 2 * cornerSize; @@ -206,21 +196,21 @@ public class NinePatch implements BackgroundPainter { int tileHeight = Math.min(heightLeft, tileSize); float vo = (tileSize - tileHeight) * px; // Used to remove unnecessary pixels on the Y axis - ScreenDrawing.texturedRect(left, y1 + j * tileSize, cornerSize, tileHeight, texture, 0, uv1, uv1, uv2 - vo, 0xFF_FFFFFF); - ScreenDrawing.texturedRect(x2, y1 + j * tileSize, cornerSize, tileHeight, texture, uv2, uv1, 1, uv2 - vo, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, left, y1 + j * tileSize, cornerSize, tileHeight, texture, 0, uv1, uv1, uv2 - vo, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, x2, y1 + j * tileSize, cornerSize, tileHeight, texture, uv2, uv1, 1, uv2 - vo, 0xFF_FFFFFF); - ScreenDrawing.texturedRect(x1 + i * tileSize, y1 + j * tileSize, tileWidth, tileHeight, texture, uv1, uv1, uv2 - uo, uv2 - vo, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, x1 + i * tileSize, y1 + j * tileSize, tileWidth, tileHeight, texture, uv1, uv1, uv2 - uo, uv2 - vo, 0xFF_FFFFFF); heightLeft -= tileSize; } widthLeft -= tileSize; } } else { - ScreenDrawing.texturedRect(x1, top, width - 2 * cornerSize, cornerSize, texture, uv1, 0, uv2, uv1, 0xFF_FFFFFF); - ScreenDrawing.texturedRect(left, y1, cornerSize, height - 2 * cornerSize, texture, 0, uv1, uv1, uv2, 0xFF_FFFFFF); - ScreenDrawing.texturedRect(x1, y2, width - 2 * cornerSize, cornerSize, texture, uv1, uv2, uv2, 1, 0xFF_FFFFFF); - ScreenDrawing.texturedRect(x2, y1, cornerSize, height - 2 * cornerSize, texture, uv2, uv1, 1, uv2, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, x1, top, width - 2 * cornerSize, cornerSize, texture, uv1, 0, uv2, uv1, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, left, y1, cornerSize, height - 2 * cornerSize, texture, 0, uv1, uv1, uv2, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, x1, y2, width - 2 * cornerSize, cornerSize, texture, uv1, uv2, uv2, 1, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, x2, y1, cornerSize, height - 2 * cornerSize, texture, uv2, uv1, 1, uv2, 0xFF_FFFFFF); - ScreenDrawing.texturedRect(x1, y1, width - 2 * cornerSize, height - 2 * cornerSize, texture, uv1, uv1, uv2, uv2, 0xFF_FFFFFF); + ScreenDrawing.texturedRect(matrices, x1, y1, width - 2 * cornerSize, height - 2 * cornerSize, texture, uv1, uv1, uv2, uv2, 0xFF_FFFFFF); } } @@ -239,8 +229,15 @@ public class NinePatch implements BackgroundPainter { */ TILING; + /** + * Deserializes a nine-patch mode from a string. + * + * @param str the mode string + * @return the mode, or null if the string is invalid + * @since 4.0.0 + */ @Nullable - static Mode fromString(String str) { + public static Mode fromString(String str) { if (str == null) return null; if (str.equalsIgnoreCase("stretching")) return STRETCHING; @@ -249,84 +246,4 @@ public class NinePatch implements BackgroundPainter { return null; } } - - public static class TextureProperties { - public static final TextureProperties DEFAULT = new TextureProperties(Mode.STRETCHING); - - private final Mode mode; - - public TextureProperties(Mode mode) { - this.mode = mode; - } - - public Mode getMode() { - return mode; - } - } - - public static class MetadataLoader extends SinglePreparationResourceReloadListener<Map<Identifier, Properties>> implements IdentifiableResourceReloadListener { - public static final MetadataLoader INSTANCE = new MetadataLoader(); - - private static final Identifier ID = new Identifier("libgui", "9patch_metadata"); - private static final String SUFFIX = ".9patch"; - - private Map<Identifier, TextureProperties> properties = Collections.emptyMap(); - - public TextureProperties getProperties(Identifier texture) { - return properties.getOrDefault(texture, TextureProperties.DEFAULT); - } - - @Override - public Identifier getFabricId() { - return ID; - } - - @Override - protected Map<Identifier, Properties> prepare(ResourceManager manager, Profiler profiler) { - Collection<Identifier> ids = manager.findResources("textures", s -> s.endsWith(SUFFIX)); - Map<Identifier, Properties> result = new HashMap<>(); - - for (Identifier input : ids) { - try (Resource resource = manager.getResource(input); - InputStream stream = resource.getInputStream()) { - Properties props = new Properties(); - props.load(stream); - Identifier textureId = new Identifier(input.getNamespace(), input.getPath().substring(0, input.getPath().length() - SUFFIX.length())); - result.put(textureId, props); - } catch (Exception e) { - LibGuiClient.logger.error("Error while loading metadata file {}, skipping...", input, e); - } - } - - return result; - } - - @Override - protected void apply(Map<Identifier, Properties> meta, ResourceManager manager, Profiler profiler) { - properties = new HashMap<>(); - for (Map.Entry<Identifier, Properties> entry : meta.entrySet()) { - Identifier id = entry.getKey(); - Properties props = entry.getValue(); - - Mode mode = TextureProperties.DEFAULT.getMode(); -// float cornerUv = TextureProperties.DEFAULT.getCornerUv(); - - if (props.containsKey("mode")) { - String modeStr = props.getProperty("mode"); - mode = Mode.fromString(modeStr); - if (mode == null) { - LibGuiClient.logger.error("Invalid mode '{}' in nine-patch metadata file for texture {}", modeStr, id); - continue; - } - } - -// if (props.containsKey("cornerUv")) { -// cornerUv = Float.parseFloat(props.getProperty("cornerUv")); -// } - - TextureProperties texProperties = new TextureProperties(mode); - properties.put(id, texProperties); - } - } - } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/ScreenDrawing.java b/src/main/java/io/github/cottonmc/cotton/gui/client/ScreenDrawing.java index f31a046..f121c47 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/ScreenDrawing.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/client/ScreenDrawing.java @@ -5,24 +5,33 @@ import com.mojang.blaze3d.systems.RenderSystem; import net.minecraft.client.MinecraftClient; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormats; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.OrderedText; +import net.minecraft.text.Style; import net.minecraft.util.Identifier; +import net.minecraft.util.math.Matrix4f; +import io.github.cottonmc.cotton.gui.impl.CottonScreenImpl; import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; import io.github.cottonmc.cotton.gui.widget.data.Texture; -import org.lwjgl.opengl.GL11; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; /** * {@code ScreenDrawing} contains utility methods for drawing contents on a screen. */ public class ScreenDrawing { + private static final Logger LOGGER = LogManager.getLogger(); + private ScreenDrawing() {} /** * Draws a textured rectangle. * + * @param matrices the rendering matrix stack * @param x the x coordinate of the box on-screen * @param y the y coordinate of the box on-screen * @param width the width of the box on-screen @@ -30,13 +39,14 @@ public class ScreenDrawing { * @param texture the Identifier for the texture * @param color a color to tint the texture. This can be transparent! Use 0xFF_FFFFFF if you don't want a color tint */ - public static void texturedRect(int x, int y, int width, int height, Identifier texture, int color) { - texturedRect(x, y, width, height, texture, 0, 0, 1, 1, color, 1.0f); + public static void texturedRect(MatrixStack matrices, int x, int y, int width, int height, Identifier texture, int color) { + texturedRect(matrices, x, y, width, height, texture, 0, 0, 1, 1, color, 1.0f); } /** * Draws a textured rectangle. * + * @param matrices the rendering matrix stack * @param x the x coordinate of the box on-screen * @param y the y coordinate of the box on-screen * @param width the width of the box on-screen @@ -46,13 +56,14 @@ public class ScreenDrawing { * @param opacity opacity of the drawn texture. (0f is fully opaque and 1f is fully visible) * @since 2.0.0 */ - public static void texturedRect(int x, int y, int width, int height, Identifier texture, int color, float opacity) { - texturedRect(x, y, width, height, texture, 0, 0, 1, 1, color, opacity); + public static void texturedRect(MatrixStack matrices, int x, int y, int width, int height, Identifier texture, int color, float opacity) { + texturedRect(matrices, x, y, width, height, texture, 0, 0, 1, 1, color, opacity); } /** * Draws a textured rectangle. * + * @param matrices the rendering matrix stack * @param x the x coordinate of the box on-screen * @param y the y coordinate of the box on-screen * @param width the width of the box on-screen @@ -64,13 +75,14 @@ public class ScreenDrawing { * @param v2 the bottom edge of the texture * @param color a color to tint the texture. This can be transparent! Use 0xFF_FFFFFF if you don't want a color tint */ - public static void texturedRect(int x, int y, int width, int height, Identifier texture, float u1, float v1, float u2, float v2, int color) { - texturedRect(x, y, width, height, texture, u1, v1, u2, v2, color, 1.0f); + public static void texturedRect(MatrixStack matrices, int x, int y, int width, int height, Identifier texture, float u1, float v1, float u2, float v2, int color) { + texturedRect(matrices, x, y, width, height, texture, u1, v1, u2, v2, color, 1.0f); } /** * Draws a textured rectangle. * + * @param matrices the rendering matrix stack * @param x the x coordinate of the box on-screen * @param y the y coordinate of the box on-screen * @param width the width of the box on-screen @@ -79,13 +91,14 @@ public class ScreenDrawing { * @param color a color to tint the texture. This can be transparent! Use 0xFF_FFFFFF if you don't want a color tint * @since 3.0.0 */ - public static void texturedRect(int x, int y, int width, int height, Texture texture, int color) { - texturedRect(x, y, width, height, texture, color, 1.0f); + public static void texturedRect(MatrixStack matrices, int x, int y, int width, int height, Texture texture, int color) { + texturedRect(matrices, x, y, width, height, texture, color, 1.0f); } /** * Draws a textured rectangle. * + * @param matrices the rendering matrix stack * @param x the x coordinate of the box on-screen * @param y the y coordinate of the box on-screen * @param width the width of the box on-screen @@ -95,13 +108,14 @@ public class ScreenDrawing { * @param opacity opacity of the drawn texture. (0f is fully opaque and 1f is fully visible) * @since 3.0.0 */ - public static void texturedRect(int x, int y, int width, int height, Texture texture, int color, float opacity) { - texturedRect(x, y, width, height, texture.image, texture.u1, texture.v1, texture.u2, texture.v2, color, opacity); + public static void texturedRect(MatrixStack matrices, int x, int y, int width, int height, Texture texture, int color, float opacity) { + texturedRect(matrices, x, y, width, height, texture.image, texture.u1, texture.v1, texture.u2, texture.v2, color, opacity); } /** * Draws a textured rectangle. * + * @param matrices the rendering matrix stack * @param x the x coordinate of the box on-screen * @param y the y coordinate of the box on-screen * @param width the width of the box on-screen @@ -115,7 +129,7 @@ public class ScreenDrawing { * @param opacity opacity of the drawn texture. (0f is fully opaque and 1f is fully visible) * @since 2.0.0 */ - public static void texturedRect(int x, int y, int width, int height, Identifier texture, float u1, float v1, float u2, float v2, int color, float opacity) { + public static void texturedRect(MatrixStack matrices, int x, int y, int width, int height, Identifier texture, float u1, float v1, float u2, float v2, int color, float opacity) { MinecraftClient.getInstance().getTextureManager().bindTexture(texture); //float scale = 0.00390625F; @@ -128,14 +142,15 @@ public class ScreenDrawing { float b = (color & 255) / 255.0F; Tessellator tessellator = Tessellator.getInstance(); BufferBuilder buffer = tessellator.getBuffer(); + Matrix4f model = matrices.peek().getModel(); RenderSystem.enableBlend(); //GlStateManager.disableTexture2D(); RenderSystem.blendFuncSeparate(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ZERO); - buffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR_TEXTURE); //I thought GL_QUADS was deprecated but okay, sure. - buffer.vertex(x, y + height, 0).color(r, g, b, opacity).texture(u1, v2).next(); - buffer.vertex(x + width, y + height, 0).color(r, g, b, opacity).texture(u2, v2).next(); - buffer.vertex(x + width, y, 0).color(r, g, b, opacity).texture(u2, v1).next(); - buffer.vertex(x, y, 0).color(r, g, b, opacity).texture(u1, v1).next(); + buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR_TEXTURE); //I thought GL_QUADS was deprecated but okay, sure. + buffer.vertex(model, x, y + height, 0).color(r, g, b, opacity).texture(u1, v2).next(); + buffer.vertex(model, x + width, y + height, 0).color(r, g, b, opacity).texture(u2, v2).next(); + buffer.vertex(model, x + width, y, 0).color(r, g, b, opacity).texture(u2, v1).next(); + buffer.vertex(model, x, y, 0).color(r, g, b, opacity).texture(u1, v1).next(); tessellator.draw(); //GlStateManager.enableTexture2D(); RenderSystem.disableBlend(); @@ -145,6 +160,8 @@ public class ScreenDrawing { * Draws a textured rectangle with UV values based on the width and height. * * <p>If the texture is 256x256, this draws the texture at one pixel per texel. + * + * @param matrices the rendering matrix stack * @param x the x coordinate of the box on-screen * @param y the y coordinate of the box on-screen * @param width the width of the box on-screen @@ -154,9 +171,9 @@ public class ScreenDrawing { * @param textureY the y offset into the texture * @param color a color to tint the texture. This can be transparent! Use 0xFF_FFFFFF if you don't want a color tint */ - public static void texturedGuiRect(int x, int y, int width, int height, Identifier texture, int textureX, int textureY, int color) { + public static void texturedGuiRect(MatrixStack matrices, int x, int y, int width, int height, Identifier texture, int textureX, int textureY, int color) { float px = 1/256f; - texturedRect(x, y, width, height, texture, textureX*px, textureY*px, (textureX+width)*px, (textureY+height)*px, color); + texturedRect(matrices, x, y, width, height, texture, textureX*px, textureY*px, (textureX+width)*px, (textureY+height)*px, color); } /** @@ -164,21 +181,22 @@ public class ScreenDrawing { * * <p>If the texture is 256x256, this draws the texture at one pixel per texel. * - * @param left the x coordinate of the box on-screen - * @param top the y coordinate of the box on-screen - * @param width the width of the box on-screen - * @param height the height of the box on-screen - * @param texture the Identifier for the texture - * @param color a color to tint the texture. This can be transparent! Use 0xFF_FFFFFF if you don't want a color tint + * @param matrices the rendering matrix stack + * @param left the x coordinate of the box on-screen + * @param top the y coordinate of the box on-screen + * @param width the width of the box on-screen + * @param height the height of the box on-screen + * @param texture the Identifier for the texture + * @param color a color to tint the texture. This can be transparent! Use 0xFF_FFFFFF if you don't want a color tint */ - public static void texturedGuiRect(int left, int top, int width, int height, Identifier texture, int color) { - texturedGuiRect(left, top, width, height, texture, 0, 0, color); + public static void texturedGuiRect(MatrixStack matrices, int left, int top, int width, int height, Identifier texture, int color) { + texturedGuiRect(matrices, left, top, width, height, texture, 0, 0, color); } /** * Draws an untextured rectangle of the specified RGB color. */ - public static void coloredRect(int left, int top, int width, int height, int color) { + public static void coloredRect(MatrixStack matrices, int left, int top, int width, int height, int color) { if (width <= 0) width = 1; if (height <= 0) height = 1; @@ -188,33 +206,20 @@ public class ScreenDrawing { float b = (color & 255) / 255.0F; Tessellator tessellator = Tessellator.getInstance(); BufferBuilder buffer = tessellator.getBuffer(); + Matrix4f model = matrices.peek().getModel(); RenderSystem.enableBlend(); RenderSystem.disableTexture(); RenderSystem.blendFuncSeparate(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ZERO); - buffer.begin(GL11.GL_QUADS, VertexFormats.POSITION_COLOR); //I thought GL_QUADS was deprecated but okay, sure. - buffer.vertex(left, top + height, 0.0D).color(r, g, b, a).next(); - buffer.vertex(left + width, top + height, 0.0D).color(r, g, b, a).next(); - buffer.vertex(left + width, top, 0.0D).color(r, g, b, a).next(); - buffer.vertex(left, top, 0.0D).color(r, g, b, a).next(); + buffer.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); //I thought GL_QUADS was deprecated but okay, sure. + buffer.vertex(model, left, top + height, 0).color(r, g, b, a).next(); + buffer.vertex(model, left + width, top + height, 0).color(r, g, b, a).next(); + buffer.vertex(model, left + width, top, 0).color(r, g, b, a).next(); + buffer.vertex(model, left, top, 0).color(r, g, b, a).next(); tessellator.draw(); RenderSystem.enableTexture(); RenderSystem.disableBlend(); } - public static void maskedRect(Identifier mask, Identifier texture, int left, int top, int width, int height) { - - - texturedRect(left, top, width, height, mask, 0, 0, 1, 1, 0xFFFFFFFF); //TODO: 7 Z - - RenderSystem.enableDepthTest(); - RenderSystem.depthFunc(GL11.GL_EQUAL); - - texturedRect(left, top, width, height, texture, 0, 0, 1, 1, 0xFFFFFFFF); //, 7); - - RenderSystem.depthFunc(GL11.GL_LESS); - RenderSystem.disableDepthTest(); - } - /** * Draws a rectangle for a Fluid, because fluids are tough. */ @@ -256,82 +261,86 @@ public class ScreenDrawing { /** * Draws a beveled, round rectangle that is substantially similar to default Minecraft UI panels. * - * @param x the X position of the panel - * @param y the Y position of the panel - * @param width the width of the panel - * @param height the height of the panel + * @param matrices the rendering matrix stack + * @param x the X position of the panel + * @param y the Y position of the panel + * @param width the width of the panel + * @param height the height of the panel */ - public static void drawGuiPanel(int x, int y, int width, int height) { - if (LibGuiClient.config.darkMode) drawGuiPanel(x, y, width, height, 0xFF0B0B0B, 0xFF2F2F2F, 0xFF414141, 0xFF000000); - else drawGuiPanel(x, y, width, height, 0xFF555555, 0xFFC6C6C6, 0xFFFFFFFF, 0xFF000000); + public static void drawGuiPanel(MatrixStack matrices, int x, int y, int width, int height) { + if (LibGui.isDarkMode()) drawGuiPanel(matrices, x, y, width, height, 0xFF0B0B0B, 0xFF2F2F2F, 0xFF414141, 0xFF000000); + else drawGuiPanel(matrices, x, y, width, height, 0xFF555555, 0xFFC6C6C6, 0xFFFFFFFF, 0xFF000000); } /** * Draws a beveled, round, and colored rectangle that is substantially similar to default Minecraft UI panels. * + * @param matrices the rendering matrix stack * @param x the X position of the panel * @param y the Y position of the panel * @param width the width of the panel * @param height the height of the panel * @param panelColor the panel ARGB color */ - public static void drawGuiPanel(int x, int y, int width, int height, int panelColor) { + public static void drawGuiPanel(MatrixStack matrices, int x, int y, int width, int height, int panelColor) { int shadowColor = multiplyColor(panelColor, 0.50f); int hilightColor = multiplyColor(panelColor, 1.25f); - drawGuiPanel(x, y, width, height, shadowColor, panelColor, hilightColor, 0xFF000000); + drawGuiPanel(matrices, x, y, width, height, shadowColor, panelColor, hilightColor, 0xFF000000); } /** * Draws a beveled, round rectangle with custom edge colors that is substantially similar to default Minecraft UI panels. * - * @param x the X position of the panel - * @param y the Y position of the panel - * @param width the width of the panel - * @param height the height of the panel - * @param shadow the bottom/right shadow ARGB color - * @param panel the center ARGB color - * @param hilight the top/left hilight ARGB color - * @param outline the outline ARGB color + * @param matrices the rendering matrix stack + * @param x the X position of the panel + * @param y the Y position of the panel + * @param width the width of the panel + * @param height the height of the panel + * @param shadow the bottom/right shadow ARGB color + * @param panel the center ARGB color + * @param hilight the top/left hilight ARGB color + * @param outline the outline ARGB color */ - public static void drawGuiPanel(int x, int y, int width, int height, int shadow, int panel, int hilight, int outline) { - coloredRect(x + 3, y + 3, width - 6, height - 6, panel); //Main panel area - - coloredRect(x + 2, y + 1, width - 4, 2, hilight); //Top hilight - coloredRect(x + 2, y + height - 3, width - 4, 2, shadow); //Bottom shadow - coloredRect(x + 1, y + 2, 2, height - 4, hilight); //Left hilight - coloredRect(x + width - 3, y + 2, 2, height - 4, shadow); //Right shadow - coloredRect(x + width - 3, y + 2, 1, 1, panel); //Topright non-hilight/non-shadow transition pixel - coloredRect(x + 2, y + height - 3, 1, 1, panel); //Bottomleft non-hilight/non-shadow transition pixel - coloredRect(x + 3, y + 3, 1, 1, hilight); //Topleft round hilight pixel - coloredRect(x + width - 4, y + height - 4, 1, 1, shadow); //Bottomright round shadow pixel - - coloredRect(x + 2, y, width - 4, 1, outline); //Top outline - coloredRect(x, y + 2, 1, height - 4, outline); //Left outline - coloredRect(x + width - 1, y + 2, 1, height - 4, outline); //Right outline - coloredRect(x + 2, y + height - 1, width - 4, 1, outline); //Bottom outline - coloredRect(x + 1, y + 1, 1, 1, outline); //Topleft round pixel - coloredRect(x + 1, y + height - 2, 1, 1, outline); //Bottomleft round pixel - coloredRect(x + width - 2, y + 1, 1, 1, outline); //Topright round pixel - coloredRect(x + width - 2, y + height - 2, 1, 1, outline); //Bottomright round pixel + public static void drawGuiPanel(MatrixStack matrices, int x, int y, int width, int height, int shadow, int panel, int hilight, int outline) { + coloredRect(matrices, x + 3, y + 3, width - 6, height - 6, panel); //Main panel area + + coloredRect(matrices, x + 2, y + 1, width - 4, 2, hilight); //Top hilight + coloredRect(matrices, x + 2, y + height - 3, width - 4, 2, shadow); //Bottom shadow + coloredRect(matrices, x + 1, y + 2, 2, height - 4, hilight); //Left hilight + coloredRect(matrices, x + width - 3, y + 2, 2, height - 4, shadow); //Right shadow + coloredRect(matrices, x + width - 3, y + 2, 1, 1, panel); //Topright non-hilight/non-shadow transition pixel + coloredRect(matrices, x + 2, y + height - 3, 1, 1, panel); //Bottomleft non-hilight/non-shadow transition pixel + coloredRect(matrices, x + 3, y + 3, 1, 1, hilight); //Topleft round hilight pixel + coloredRect(matrices, x + width - 4, y + height - 4, 1, 1, shadow); //Bottomright round shadow pixel + + coloredRect(matrices, x + 2, y, width - 4, 1, outline); //Top outline + coloredRect(matrices, x, y + 2, 1, height - 4, outline); //Left outline + coloredRect(matrices, x + width - 1, y + 2, 1, height - 4, outline); //Right outline + coloredRect(matrices, x + 2, y + height - 1, width - 4, 1, outline); //Bottom outline + coloredRect(matrices, x + 1, y + 1, 1, 1, outline); //Topleft round pixel + coloredRect(matrices, x + 1, y + height - 2, 1, 1, outline); //Bottomleft round pixel + coloredRect(matrices, x + width - 2, y + 1, 1, 1, outline); //Topright round pixel + coloredRect(matrices, x + width - 2, y + height - 2, 1, 1, outline); //Bottomright round pixel } /** * Draws a default-sized recessed itemslot panel */ - public static void drawBeveledPanel(int x, int y) { - drawBeveledPanel(x, y, 18, 18, 0xFF373737, 0xFF8b8b8b, 0xFFFFFFFF); + public static void drawBeveledPanel(MatrixStack matrices, int x, int y) { + drawBeveledPanel(matrices, x, y, 18, 18, 0xFF373737, 0xFF8b8b8b, 0xFFFFFFFF); } /** * Draws a default-color recessed itemslot panel of variable size */ - public static void drawBeveledPanel(int x, int y, int width, int height) { - drawBeveledPanel(x, y, width, height, 0xFF373737, 0xFF8b8b8b, 0xFFFFFFFF); + public static void drawBeveledPanel(MatrixStack matrices, int x, int y, int width, int height) { + drawBeveledPanel(matrices, x, y, width, height, 0xFF373737, 0xFF8b8b8b, 0xFFFFFFFF); } /** * Draws a generalized-case beveled panel. Can be inset or outset depending on arguments. + * @param matrices the rendering matrix stack * @param x x coordinate of the topleft corner * @param y y coordinate of the topleft corner * @param width width of the panel @@ -340,12 +349,12 @@ public class ScreenDrawing { * @param panel color of the panel area * @param bottomright color of the bottom/right bevel */ - public static void drawBeveledPanel(int x, int y, int width, int height, int topleft, int panel, int bottomright) { - coloredRect(x, y, width, height, panel); //Center panel - coloredRect(x, y, width - 1, 1, topleft); //Top shadow - coloredRect(x, y + 1, 1, height - 2, topleft); //Left shadow - coloredRect(x + width - 1, y + 1, 1, height - 1, bottomright); //Right hilight - coloredRect(x + 1, y + height - 1, width - 1, 1, bottomright); //Bottom hilight + public static void drawBeveledPanel(MatrixStack matrices, int x, int y, int width, int height, int topleft, int panel, int bottomright) { + coloredRect(matrices, x, y, width, height, panel); //Center panel + coloredRect(matrices, x, y, width - 1, 1, topleft); //Top shadow + coloredRect(matrices, x, y + 1, 1, height - 2, topleft); //Left shadow + coloredRect(matrices, x + width - 1, y + 1, 1, height - 1, bottomright); //Right hilight + coloredRect(matrices, x + 1, y + height - 1, width - 1, 1, bottomright); //Bottom hilight } /** @@ -503,6 +512,28 @@ public class ScreenDrawing { MinecraftClient.getInstance().textRenderer.draw(matrices, text, x, y, color); } + /** + * Draws the text hover effects for a text style. + * + * <p>This method should only be called from a widget in a screen. + * For example, there will be nothing drawn in HUDs. + * + * @param matrices the rendering matrix stack + * @param textStyle the text style + * @param x the X position + * @param y the Y position + * @since 4.0.0 + */ + public static void drawTextHover(MatrixStack matrices, @Nullable Style textStyle, int x, int y) { + CottonScreenImpl screen = (CottonScreenImpl) MinecraftClient.getInstance().currentScreen; + + if (screen != null) { + screen.renderTextHover(matrices, textStyle, x, y); + } else { + LOGGER.warn("Rendering text hover effects outside of a screen!"); + } + } + public static int colorAtOpacity(int opaque, float opacity) { if (opacity<0.0f) opacity=0.0f; if (opacity>1.0f) opacity=1.0f; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/TextHoverRendererScreen.java b/src/main/java/io/github/cottonmc/cotton/gui/client/TextHoverRendererScreen.java deleted file mode 100644 index d6b4ca1..0000000 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/TextHoverRendererScreen.java +++ /dev/null @@ -1,11 +0,0 @@ -package io.github.cottonmc.cotton.gui.client; - -import net.minecraft.client.util.math.MatrixStack; -import net.minecraft.text.Style; - -/** - * Implemented by LibGui screens to access {@code Screen.renderTextHoverEffect()}. - */ -public interface TextHoverRendererScreen { - void renderTextHover(MatrixStack matrices, Style textStyle, int x, int y); -} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/package-info.java b/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/package-info.java deleted file mode 100644 index ad040bf..0000000 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Mod Menu support for LibGui. - */ -package io.github.cottonmc.cotton.gui.client.modmenu; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/CottonScreenImpl.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/CottonScreenImpl.java new file mode 100644 index 0000000..69a6f77 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/CottonScreenImpl.java @@ -0,0 +1,24 @@ +package io.github.cottonmc.cotton.gui.impl; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Style; + +import io.github.cottonmc.cotton.gui.widget.WWidget; +import org.jetbrains.annotations.Nullable; + +@Environment(EnvType.CLIENT) +public interface CottonScreenImpl { + default Screen asScreen() { + return (Screen) this; + } + + @Nullable + WWidget getLastResponder(); + + void setLastResponder(@Nullable WWidget lastResponder); + + void renderTextHover(MatrixStack matrices, @Nullable Style textStyle, int x, int y); +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/MouseInputHandler.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/MouseInputHandler.java new file mode 100644 index 0000000..747bae8 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/MouseInputHandler.java @@ -0,0 +1,112 @@ +package io.github.cottonmc.cotton.gui.impl; + +import io.github.cottonmc.cotton.gui.GuiDescription; +import io.github.cottonmc.cotton.gui.widget.WWidget; +import io.github.cottonmc.cotton.gui.widget.data.InputResult; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Function; + +/** + * The implementation for mouse inputs. + */ +public final class MouseInputHandler { + public static void onMouseDown(GuiDescription description, CottonScreenImpl screen, int containerX, int containerY, int mouseButton) { + if (screen.getLastResponder() == null) { + WWidget lastResponder = description.getRootPanel().hit(containerX, containerY); + screen.setLastResponder(lastResponder); + if (lastResponder != null) { + runTree( + lastResponder, + widget -> widget.onMouseDown(containerX - widget.getAbsoluteX(), containerY - widget.getAbsoluteY(), mouseButton) + ); + } + } else { + // This is a drag instead + } + } + + public static void onMouseUp(GuiDescription description, CottonScreenImpl screen, int containerX, int containerY, int mouseButton) { + WWidget lastResponder = screen.getLastResponder(); + + if (lastResponder != null) { + int width = screen.asScreen().width; + int height = screen.asScreen().height; + + runTree( + lastResponder, + widget -> widget.onMouseUp(containerX - widget.getAbsoluteX(), containerY - widget.getAbsoluteY(), mouseButton) + ); + + if (containerX >= 0 && containerY >= 0 && containerX < width && containerY < height) { + runTree( + lastResponder, + widget -> widget.onClick(containerX - widget.getAbsoluteX(), containerY - widget.getAbsoluteY(), mouseButton) + ); + } + } else { + runTree( + description.getRootPanel().hit(containerX, containerY), + widget -> widget.onMouseUp(containerX - widget.getAbsoluteX(), containerY - widget.getAbsoluteY(), mouseButton) + ); + } + + screen.setLastResponder(null); + } + + public static void onMouseDrag(GuiDescription description, CottonScreenImpl screen, int containerX, int containerY, int mouseButton, double deltaX, double deltaY) { + WWidget lastResponder = screen.getLastResponder(); + + if (lastResponder != null) { + lastResponder.onMouseDrag(containerX - lastResponder.getAbsoluteX(), containerY - lastResponder.getAbsoluteY(), mouseButton, deltaX, deltaY); + } else { + int width = screen.asScreen().width; + int height = screen.asScreen().height; + + if (containerX < 0 || containerY < 0 || containerX >= width || containerY >= height) return; + + runTree( + description.getRootPanel().hit(containerX, containerY), + widget -> widget.onMouseDrag(containerX - widget.getAbsoluteX(), containerY - widget.getAbsoluteY(), mouseButton, deltaX, deltaY) + ); + } + } + + public static void onMouseScroll(GuiDescription description, int containerX, int containerY, double amount) { + runTree( + description.getRootPanel().hit(containerX, containerY), + widget -> widget.onMouseScroll(containerX - widget.getAbsoluteX(), containerY - widget.getAbsoluteY(), amount) + ); + } + + public static void onMouseMove(GuiDescription description, int containerX, int containerY) { + runTree( + description.getRootPanel().hit(containerX, containerY), + widget -> widget.onMouseMove(containerX - widget.getAbsoluteX(), containerY - widget.getAbsoluteY()) + ); + } + + /** + * Traverses the {@code function} up the widget tree until it finds a {@link InputResult#PROCESSED} result. + * + * @param bottom the starting point for the traversal + * @param function the function to run + * @return the first widget to return {@link InputResult#PROCESSED}, or null if none found. + */ + @Nullable + private static WWidget runTree(WWidget bottom, Function<WWidget, InputResult> function) { + WWidget current = bottom; + + while (current != null) { + InputResult result = function.apply(current); + + if (result == InputResult.PROCESSED) { + break; + } else { + current = current.getParent(); + } + } + + return current; + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/access/ScreenAccessor.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/access/ScreenAccessor.java new file mode 100644 index 0000000..33add9f --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/access/ScreenAccessor.java @@ -0,0 +1,16 @@ +package io.github.cottonmc.cotton.gui.impl.access; + +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.tooltip.TooltipComponent; +import net.minecraft.client.util.math.MatrixStack; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.List; + +@Mixin(Screen.class) +public interface ScreenAccessor { + @Invoker + void callRenderTooltipFromComponents(MatrixStack matrices, List<TooltipComponent> components, int x, int y); +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/access/package-info.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/access/package-info.java index 8f391fd..b98a6b8 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/impl/access/package-info.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/access/package-info.java @@ -1,4 +1,7 @@ /** * Internal implementation classes. */ +@ApiStatus.Internal package io.github.cottonmc.cotton.gui.impl.access; + +import org.jetbrains.annotations.ApiStatus; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/LibGuiClient.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/LibGuiClient.java index 80fa414..ccb4a0a 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/LibGuiClient.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/LibGuiClient.java @@ -1,4 +1,4 @@ -package io.github.cottonmc.cotton.gui.client; +package io.github.cottonmc.cotton.gui.impl.client; import net.fabricmc.api.ClientModInitializer; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; @@ -9,8 +9,8 @@ import net.minecraft.resource.ResourceType; import blue.endless.jankson.Jankson; import blue.endless.jankson.JsonElement; import blue.endless.jankson.JsonObject; -import io.github.cottonmc.cotton.gui.impl.ScreenNetworkingImpl; import io.github.cottonmc.jankson.JanksonFactory; +import io.github.cottonmc.cotton.gui.impl.ScreenNetworkingImpl; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -29,7 +29,7 @@ public class LibGuiClient implements ClientModInitializer { public void onInitializeClient() { config = loadConfig(); - ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(NinePatch.MetadataLoader.INSTANCE); + ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(NinePatchInternals.MetadataLoader.INSTANCE); ClientPlayNetworking.registerGlobalReceiver(ScreenNetworkingImpl.SCREEN_MESSAGE_S2C, (client, networkHandler, buf, responseSender) -> { ScreenNetworkingImpl.handle(client, client.player, buf); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/LibGuiConfig.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/LibGuiConfig.java index b971e31..b1985af 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/LibGuiConfig.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/LibGuiConfig.java @@ -1,4 +1,4 @@ -package io.github.cottonmc.cotton.gui.client; +package io.github.cottonmc.cotton.gui.impl.client; import blue.endless.jankson.Comment; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/client/NinePatchInternals.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/NinePatchInternals.java new file mode 100644 index 0000000..4113825 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/NinePatchInternals.java @@ -0,0 +1,103 @@ +package io.github.cottonmc.cotton.gui.impl.client; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.resource.IdentifiableResourceReloadListener; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.SinglePreparationResourceReloadListener; +import net.minecraft.util.Identifier; +import net.minecraft.util.profiler.Profiler; + +import io.github.cottonmc.cotton.gui.client.NinePatch; + +import java.io.InputStream; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +@Environment(EnvType.CLIENT) +public final class NinePatchInternals { + @Environment(EnvType.CLIENT) + public static final class MetadataLoader extends SinglePreparationResourceReloadListener<Map<Identifier, Properties>> implements IdentifiableResourceReloadListener { + public static final MetadataLoader INSTANCE = new MetadataLoader(); + + private static final Identifier ID = new Identifier("libgui", "9patch_metadata"); + private static final String SUFFIX = ".9patch"; + + private Map<Identifier, TextureProperties> properties = Collections.emptyMap(); + + public TextureProperties getProperties(Identifier texture) { + return properties.getOrDefault(texture, TextureProperties.DEFAULT); + } + + @Override + public Identifier getFabricId() { + return ID; + } + + @Override + protected Map<Identifier, Properties> prepare(ResourceManager manager, Profiler profiler) { + Collection<Identifier> ids = manager.findResources("textures", s -> s.endsWith(SUFFIX)); + Map<Identifier, Properties> result = new HashMap<>(); + + for (Identifier input : ids) { + try (Resource resource = manager.getResource(input); + InputStream stream = resource.getInputStream()) { + Properties props = new Properties(); + props.load(stream); + Identifier textureId = new Identifier(input.getNamespace(), input.getPath().substring(0, input.getPath().length() - SUFFIX.length())); + result.put(textureId, props); + } catch (Exception e) { + LibGuiClient.logger.error("Error while loading metadata file {}, skipping...", input, e); + } + } + + return result; + } + + @Override + protected void apply(Map<Identifier, Properties> meta, ResourceManager manager, Profiler profiler) { + properties = new HashMap<>(); + for (Map.Entry<Identifier, Properties> entry : meta.entrySet()) { + Identifier id = entry.getKey(); + Properties props = entry.getValue(); + + NinePatch.Mode mode = TextureProperties.DEFAULT.getMode(); + // float cornerUv = TextureProperties.DEFAULT.getCornerUv(); + + if (props.containsKey("mode")) { + String modeStr = props.getProperty("mode"); + mode = NinePatch.Mode.fromString(modeStr); + if (mode == null) { + LibGuiClient.logger.error("Invalid mode '{}' in nine-patch metadata file for texture {}", modeStr, id); + continue; + } + } + + // if (props.containsKey("cornerUv")) { + // cornerUv = Float.parseFloat(props.getProperty("cornerUv")); + // } + + TextureProperties texProperties = new TextureProperties(mode); + properties.put(id, texProperties); + } + } + } + + public static class TextureProperties { + public static final TextureProperties DEFAULT = new TextureProperties(NinePatch.Mode.STRETCHING); + + private final NinePatch.Mode mode; + + public TextureProperties(NinePatch.Mode mode) { + this.mode = mode; + } + + public NinePatch.Mode getMode() { + return mode; + } + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/modmenu/ConfigGui.java index cd3fe0a..5f3d4fa 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ConfigGui.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/modmenu/ConfigGui.java @@ -1,12 +1,12 @@ -package io.github.cottonmc.cotton.gui.client.modmenu; +package io.github.cottonmc.cotton.gui.impl.client.modmenu; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.screen.Screen; import net.minecraft.text.TranslatableText; import io.github.cottonmc.cotton.gui.client.BackgroundPainter; -import io.github.cottonmc.cotton.gui.client.LibGuiClient; import io.github.cottonmc.cotton.gui.client.LightweightGuiDescription; +import io.github.cottonmc.cotton.gui.impl.client.LibGuiClient; import io.github.cottonmc.cotton.gui.widget.WButton; import io.github.cottonmc.cotton.gui.widget.WGridPanel; import io.github.cottonmc.cotton.gui.widget.WTextField; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ModMenuSupport.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/modmenu/ModMenuSupport.java index ccdff93..82fead4 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/ModMenuSupport.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/modmenu/ModMenuSupport.java @@ -1,4 +1,4 @@ -package io.github.cottonmc.cotton.gui.client.modmenu; +package io.github.cottonmc.cotton.gui.impl.client.modmenu; import net.minecraft.text.TranslatableText; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/WKirbSprite.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/modmenu/WKirbSprite.java index 74d5357..74f0f1a 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/client/modmenu/WKirbSprite.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/modmenu/WKirbSprite.java @@ -1,11 +1,11 @@ -package io.github.cottonmc.cotton.gui.client.modmenu; +package io.github.cottonmc.cotton.gui.impl.client.modmenu; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.Identifier; -import io.github.cottonmc.cotton.gui.client.LibGuiClient; +import io.github.cottonmc.cotton.gui.client.LibGui; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import io.github.cottonmc.cotton.gui.widget.WWidget; @@ -30,7 +30,7 @@ public class WKirbSprite extends WWidget { private long lastFrame; public WKirbSprite() { - state = (LibGuiClient.config.darkMode) ? State.ASLEEP : State.AWAKE; + state = (LibGui.isDarkMode()) ? State.ASLEEP : State.AWAKE; } public void schedule(int[] frames) { @@ -60,7 +60,7 @@ public class WKirbSprite extends WWidget { if (pendingFrames.isEmpty()) { - if (LibGuiClient.config.darkMode) { + if (LibGui.isDarkMode()) { switch(state) { case AWAKE: state = State.FALLING_ASLEEP; @@ -96,7 +96,7 @@ public class WKirbSprite extends WWidget { } float offset = KIRB_WIDTH * currentFrame; - ScreenDrawing.texturedRect(x, y+8, 32, 32, KIRB, offset, 0, offset+KIRB_WIDTH, 1, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x, y+8, 32, 32, KIRB, offset, 0, offset+KIRB_WIDTH, 1, 0xFFFFFFFF); long elapsed = now - lastFrame; currentFrameTime += elapsed; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/client/modmenu/package-info.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/modmenu/package-info.java new file mode 100644 index 0000000..283aa50 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/modmenu/package-info.java @@ -0,0 +1,7 @@ +/** + * Mod Menu support for LibGui. + */ +@ApiStatus.Internal +package io.github.cottonmc.cotton.gui.impl.client.modmenu; + +import org.jetbrains.annotations.ApiStatus; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/client/package-info.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/package-info.java new file mode 100644 index 0000000..c27d30e --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/client/package-info.java @@ -0,0 +1,9 @@ +/** + * Internal implementation classes. + * + * @since 4.0.0 + */ +@ApiStatus.Internal // I hope this scares people off +package io.github.cottonmc.cotton.gui.impl.client; + +import org.jetbrains.annotations.ApiStatus; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/impl/package-info.java b/src/main/java/io/github/cottonmc/cotton/gui/impl/package-info.java index 678ba6f..298c2fc 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/impl/package-info.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/impl/package-info.java @@ -3,4 +3,7 @@ * * @since 2.0.0 */ +@ApiStatus.Internal package io.github.cottonmc.cotton.gui.impl; + +import org.jetbrains.annotations.ApiStatus; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/TooltipBuilder.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/TooltipBuilder.java index f99df0a..86b8016 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/TooltipBuilder.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/TooltipBuilder.java @@ -2,12 +2,19 @@ package io.github.cottonmc.cotton.gui.widget; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.tooltip.TooltipComponent; +import net.minecraft.client.item.TooltipData; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.texture.TextureManager; +import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.OrderedText; import net.minecraft.text.Text; import java.util.ArrayList; -import java.util.Collections; +import java.util.Arrays; import java.util.List; +import java.util.Objects; /** * A builder for widget tooltips. @@ -16,10 +23,10 @@ import java.util.List; */ @Environment(EnvType.CLIENT) public final class TooltipBuilder { - final List<OrderedText> lines = new ArrayList<>(); + final List<TooltipComponent> components = new ArrayList<>(); int size() { - return lines.size(); + return components.size(); } /** @@ -27,10 +34,12 @@ public final class TooltipBuilder { * * @param lines the lines * @return this builder + * @throws NullPointerException if the lines are null */ public TooltipBuilder add(Text... lines) { + Objects.requireNonNull(lines, "lines"); for (Text line : lines) { - this.lines.add(line.asOrderedText()); + components.add(TooltipComponent.of(line.asOrderedText())); } return this; @@ -41,10 +50,108 @@ public final class TooltipBuilder { * * @param lines the lines * @return this builder + * @throws NullPointerException if the lines are null */ public TooltipBuilder add(OrderedText... lines) { - Collections.addAll(this.lines, lines); + Objects.requireNonNull(lines, "lines"); + for (OrderedText line : lines) { + components.add(TooltipComponent.of(line)); + } + + return this; + } + + /** + * Adds the components to this builder. + * + * @param components the components + * @return this builder + * @throws NullPointerException if the components are null + * @since 4.0.0 + */ + public TooltipBuilder add(TooltipComponent... components) { + Objects.requireNonNull(components, "components"); + this.components.addAll(Arrays.asList(components)); + + return this; + } + + /** + * Adds a tooltip component created from tooltip data to this builder. + * + * @param tooltipData the data + * @return this builder + * @throws NullPointerException if the data is null + * @since 4.0.0 + */ + public TooltipBuilder add(TooltipData tooltipData) { + Objects.requireNonNull(tooltipData, "tooltipData"); + components.add(TooltipComponent.of(tooltipData)); return this; } + + /** + * Adds the widget to this builder. + * + * <p>Tooltip widgets should usually be cached inside the widget they are created in. + * + * @param widget the widget + * @return this builder + * @throws NullPointerException if the widget is null + * @since 4.0.0 + */ + public TooltipBuilder add(WWidget widget) { + Objects.requireNonNull(widget, "widget"); + components.add(new WidgetTooltipComponent(widget)); + + return this; + } + + /** + * Adds the widget to this builder and resizes it if resizeable. + * + * <p>Tooltip widgets should usually be cached inside the widget they are created in. + * + * @param widget the widget + * @param width the new width + * @param height the new height + * @return this builder + * @throws NullPointerException if the widget is null + * @since 4.0.0 + */ + public TooltipBuilder add(WWidget widget, int width, int height) { + Objects.requireNonNull(widget, "widget"); + components.add(new WidgetTooltipComponent(widget)); + + if (widget.canResize()) { + widget.setSize(width, height); + } + + return this; + } + + private static class WidgetTooltipComponent implements TooltipComponent { + private final WWidget widget; + + WidgetTooltipComponent(WWidget widget) { + this.widget = widget; + } + + @Override + public int getWidth(TextRenderer textRenderer) { + return widget.getWidth(); + } + + @Override + public int getHeight() { + return widget.getHeight(); + } + + @Override + public void drawItems(TextRenderer textRenderer, int x, int y, MatrixStack matrices, ItemRenderer itemRenderer, int z, TextureManager textureManager) { + widget.paint(matrices, x, y, /* mouse coords: nowhere in sight */ -x, -y); + widget.tick(); // Screens are ticked every time they're rendered, so why not tooltip widgets? + } + } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java index 6c422bc..b5eda0a 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WAbstractSlider.java @@ -5,6 +5,7 @@ import net.fabricmc.api.Environment; import net.minecraft.util.math.MathHelper; import io.github.cottonmc.cotton.gui.widget.data.Axis; +import io.github.cottonmc.cotton.gui.widget.data.InputResult; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; @@ -108,28 +109,31 @@ public abstract class WAbstractSlider extends WWidget { @Environment(EnvType.CLIENT) @Override - public WWidget onMouseDown(int x, int y, int button) { + public InputResult onMouseDown(int x, int y, int button) { // Check if cursor is inside or <=2px away from track if (isMouseInsideBounds(x, y)) { requestFocus(); + return InputResult.PROCESSED; } - return super.onMouseDown(x, y, button); + return InputResult.IGNORED; } @Environment(EnvType.CLIENT) @Override - public void onMouseDrag(int x, int y, int button) { + public InputResult onMouseDrag(int x, int y, int button, double deltaX, double deltaY) { if (isFocused()) { dragging = true; moveSlider(x, y); } + return InputResult.PROCESSED; } @Environment(EnvType.CLIENT) @Override - public void onClick(int x, int y, int button) { + public InputResult onClick(int x, int y, int button) { moveSlider(x, y); if (draggingFinishedListener != null) draggingFinishedListener.accept(value); + return InputResult.PROCESSED; } private void moveSlider(int x, int y) { @@ -160,15 +164,15 @@ public abstract class WAbstractSlider extends WWidget { @Environment(EnvType.CLIENT) @Override - public WWidget onMouseUp(int x, int y, int button) { + public InputResult onMouseUp(int x, int y, int button) { dragging = false; if (draggingFinishedListener != null) draggingFinishedListener.accept(value); - return super.onMouseUp(x, y, button); + return InputResult.PROCESSED; } @Environment(EnvType.CLIENT) @Override - public void onMouseScroll(int x, int y, double amount) { + public InputResult onMouseScroll(int x, int y, double amount) { if (direction == Direction.LEFT || direction == Direction.DOWN) { amount = -amount; } @@ -180,6 +184,7 @@ public abstract class WAbstractSlider extends WWidget { onValueChanged(value); pendingDraggingFinishedFromScrolling = true; } + return InputResult.PROCESSED; } @Environment(EnvType.CLIENT) diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WBar.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WBar.java index 13cf16b..1aea8ec 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WBar.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WBar.java @@ -113,9 +113,9 @@ public class WBar extends WWidget { @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { if (bg!=null) { - ScreenDrawing.texturedRect(x, y, getWidth(), getHeight(), bg, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x, y, getWidth(), getHeight(), bg, 0xFFFFFFFF); } else { - ScreenDrawing.coloredRect(x, y, getWidth(), getHeight(), ScreenDrawing.colorAtOpacity(0x000000, 0.25f)); + ScreenDrawing.coloredRect(matrices, x, y, getWidth(), getHeight(), ScreenDrawing.colorAtOpacity(0x000000, 0.25f)); } float percent = properties.get(field) / (float) properties.get(max); @@ -135,25 +135,25 @@ public class WBar extends WWidget { int top = y + getHeight(); top -= barSize; if (bar!=null) { - ScreenDrawing.texturedRect(left, top, getWidth(), barSize, bar.image, bar.u1, MathHelper.lerp(percent, bar.v2, bar.v1), bar.u2, bar.v2, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, left, top, getWidth(), barSize, bar.image, bar.u1, MathHelper.lerp(percent, bar.v2, bar.v1), bar.u2, bar.v2, 0xFFFFFFFF); } else { - ScreenDrawing.coloredRect(left, top, getWidth(), barSize, ScreenDrawing.colorAtOpacity(0xFFFFFF, 0.5f)); + ScreenDrawing.coloredRect(matrices, left, top, getWidth(), barSize, ScreenDrawing.colorAtOpacity(0xFFFFFF, 0.5f)); } break; } case RIGHT: { if (bar!=null) { - ScreenDrawing.texturedRect(x, y, barSize, getHeight(), bar.image, bar.u1, bar.v1, MathHelper.lerp(percent, bar.u1, bar.u2), bar.v2, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x, y, barSize, getHeight(), bar.image, bar.u1, bar.v1, MathHelper.lerp(percent, bar.u1, bar.u2), bar.v2, 0xFFFFFFFF); } else { - ScreenDrawing.coloredRect(x, y, barSize, getHeight(), ScreenDrawing.colorAtOpacity(0xFFFFFF, 0.5f)); + ScreenDrawing.coloredRect(matrices, x, y, barSize, getHeight(), ScreenDrawing.colorAtOpacity(0xFFFFFF, 0.5f)); } break; } case DOWN: { if (bar!=null) { - ScreenDrawing.texturedRect(x, y, getWidth(), barSize, bar.image, bar.u1, bar.v1, bar.u2, MathHelper.lerp(percent, bar.v1, bar.v2), 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x, y, getWidth(), barSize, bar.image, bar.u1, bar.v1, bar.u2, MathHelper.lerp(percent, bar.v1, bar.v2), 0xFFFFFFFF); } else { - ScreenDrawing.coloredRect(x, y, getWidth(), barSize, ScreenDrawing.colorAtOpacity(0xFFFFFF, 0.5f)); + ScreenDrawing.coloredRect(matrices, x, y, getWidth(), barSize, ScreenDrawing.colorAtOpacity(0xFFFFFF, 0.5f)); } break; } @@ -162,9 +162,9 @@ public class WBar extends WWidget { int top = y; left -= barSize; if (bar!=null) { - ScreenDrawing.texturedRect(left, top, barSize, getHeight(), bar.image, MathHelper.lerp(percent, bar.u2, bar.u1), bar.v1, bar.u2, bar.v2, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, left, top, barSize, getHeight(), bar.image, MathHelper.lerp(percent, bar.u2, bar.u1), bar.v1, bar.u2, bar.v2, 0xFFFFFFFF); } else { - ScreenDrawing.coloredRect(left, top, barSize, getHeight(), ScreenDrawing.colorAtOpacity(0xFFFFFF, 0.5f)); + ScreenDrawing.coloredRect(matrices, left, top, barSize, getHeight(), ScreenDrawing.colorAtOpacity(0xFFFFFF, 0.5f)); } break; } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java index 65dde6f..a8db003 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WButton.java @@ -11,6 +11,7 @@ import net.minecraft.text.Text; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; +import io.github.cottonmc.cotton.gui.widget.data.InputResult; import io.github.cottonmc.cotton.gui.widget.icon.Icon; import org.jetbrains.annotations.Nullable; @@ -93,8 +94,8 @@ public class WButton extends WWidget { float buttonEndLeft = (200-(getWidth()/2)) * px; - ScreenDrawing.texturedRect(x, y, getWidth()/2, 20, AbstractButtonWidget.WIDGETS_LOCATION, buttonLeft, buttonTop, buttonLeft+buttonWidth, buttonTop+buttonHeight, 0xFFFFFFFF); - ScreenDrawing.texturedRect(x+(getWidth()/2), y, getWidth()/2, 20, AbstractButtonWidget.WIDGETS_LOCATION, buttonEndLeft, buttonTop, 200*px, buttonTop+buttonHeight, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x, y, getWidth()/2, 20, AbstractButtonWidget.WIDGETS_LOCATION, buttonLeft, buttonTop, buttonLeft+buttonWidth, buttonTop+buttonHeight, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x+(getWidth()/2), y, getWidth()/2, 20, AbstractButtonWidget.WIDGETS_LOCATION, buttonEndLeft, buttonTop, 200*px, buttonTop+buttonHeight, 0xFFFFFFFF); if (icon != null) { icon.paint(matrices, x + 1, y + 1, 16); @@ -120,7 +121,7 @@ public class WButton extends WWidget { @Environment(EnvType.CLIENT) @Override - public void onClick(int x, int y, int button) { + public InputResult onClick(int x, int y, int button) { super.onClick(x, y, button); if (enabled && isWithinBounds(x, y)) { @@ -128,6 +129,7 @@ public class WButton extends WWidget { if (onClick!=null) onClick.run(); } + return InputResult.PROCESSED; } @Environment(EnvType.CLIENT) diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WCardPanel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WCardPanel.java index 3d1da6a..8caad27 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WCardPanel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WCardPanel.java @@ -178,16 +178,6 @@ public class WCardPanel extends WPanel { card.validate(c); if (getSelectedCard() != card) card.onHidden(); } - - if (c != null) createPeers(c); - } - - @SuppressWarnings("deprecation") - @Override - public void createPeers(GuiDescription c) { - for (WWidget card : cards) { - card.createPeers(c); - } } @Environment(EnvType.CLIENT) diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WClippedPanel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WClippedPanel.java index 6daf600..a594fc2 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WClippedPanel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WClippedPanel.java @@ -13,7 +13,7 @@ public class WClippedPanel extends WPanel { @Environment(EnvType.CLIENT) @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { - if (getBackgroundPainter()!=null) getBackgroundPainter().paintBackground(x, y, this); + if (getBackgroundPainter()!=null) getBackgroundPainter().paintBackground(matrices, x, y, this); Scissors.push(x, y, width, height); for(WWidget child : children) { diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WDynamicLabel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WDynamicLabel.java index 0412b83..6099022 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WDynamicLabel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WDynamicLabel.java @@ -4,7 +4,7 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.util.math.MatrixStack; -import io.github.cottonmc.cotton.gui.client.LibGuiClient; +import io.github.cottonmc.cotton.gui.client.LibGui; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; @@ -40,7 +40,7 @@ public class WDynamicLabel extends WWidget { @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { String tr = text.get(); - ScreenDrawing.drawString(matrices, tr, alignment, x, y, this.getWidth(), LibGuiClient.config.darkMode ? darkmodeColor : color); + ScreenDrawing.drawString(matrices, tr, alignment, x, y, this.getWidth(), LibGui.isDarkMode() ? darkmodeColor : color); } @Override diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java index 45fc896..1667bee 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WItemSlot.java @@ -328,7 +328,7 @@ public class WItemSlot extends WWidget { @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { if (backgroundPainter != null) { - backgroundPainter.paintBackground(x, y, this); + backgroundPainter.paintBackground(matrices, x, y, this); } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabel.java index 0bdf81a..2943f1b 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabel.java @@ -10,10 +10,10 @@ import net.minecraft.text.LiteralText; import net.minecraft.text.Style; import net.minecraft.text.Text; -import io.github.cottonmc.cotton.gui.client.LibGuiClient; +import io.github.cottonmc.cotton.gui.client.LibGui; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; -import io.github.cottonmc.cotton.gui.client.TextHoverRendererScreen; import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; +import io.github.cottonmc.cotton.gui.widget.data.InputResult; import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment; import org.jetbrains.annotations.Nullable; @@ -33,7 +33,7 @@ public class WLabel extends WWidget { public static final int DEFAULT_TEXT_COLOR = 0x404040; /** - * The default text color for {@linkplain io.github.cottonmc.cotton.gui.client.LibGuiConfig#darkMode dark mode} labels. + * The default text color for {@linkplain LibGui#isDarkMode() dark mode} labels. */ public static final int DEFAULT_DARKMODE_TEXT_COLOR = 0xbcbcbc; @@ -98,20 +98,15 @@ public class WLabel extends WWidget { break; } - ScreenDrawing.drawString(matrices, text.asOrderedText(), horizontalAlignment, x, y + yOffset, this.getWidth(), LibGuiClient.config.darkMode ? darkmodeColor : color); + ScreenDrawing.drawString(matrices, text.asOrderedText(), horizontalAlignment, x, y + yOffset, this.getWidth(), LibGui.isDarkMode() ? darkmodeColor : color); Style hoveredTextStyle = getTextStyleAt(mouseX, mouseY); - if (hoveredTextStyle != null) { - Screen screen = MinecraftClient.getInstance().currentScreen; - if (screen instanceof TextHoverRendererScreen) { - ((TextHoverRendererScreen) screen).renderTextHover(matrices, hoveredTextStyle, x + mouseX, y + mouseY); - } - } + ScreenDrawing.drawTextHover(matrices, hoveredTextStyle, x + mouseX, y + mouseY); } @Environment(EnvType.CLIENT) @Override - public void onClick(int x, int y, int button) { + public InputResult onClick(int x, int y, int button) { Style hoveredTextStyle = getTextStyleAt(x, y); if (hoveredTextStyle != null) { Screen screen = MinecraftClient.getInstance().currentScreen; @@ -119,6 +114,7 @@ public class WLabel extends WWidget { screen.handleTextClick(hoveredTextStyle); } } + return InputResult.PROCESSED; } /** diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java index 0c1a510..57cc8e6 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WLabeledSlider.java @@ -1,11 +1,11 @@ package io.github.cottonmc.cotton.gui.widget; -import com.mojang.blaze3d.systems.RenderSystem; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.gui.widget.AbstractButtonWidget; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.Text; +import net.minecraft.util.math.Vec3f; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import io.github.cottonmc.cotton.gui.widget.data.Axis; @@ -155,7 +155,6 @@ public class WLabeledSlider extends WAbstractSlider { return x >= 0 && x <= width && y >= 0 && y <= height; } - @SuppressWarnings("deprecation") @Environment(EnvType.CLIENT) @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { @@ -166,13 +165,13 @@ public class WLabeledSlider extends WAbstractSlider { : (direction == Direction.UP ? height - mouseY : mouseY); int rotMouseY = axis == Axis.HORIZONTAL ? mouseY : mouseX; - RenderSystem.pushMatrix(); - RenderSystem.translatef(x, y, 0); + matrices.push(); + matrices.translate(x, y, 0); if (axis == Axis.VERTICAL) { - RenderSystem.translatef(0, height, 0); - RenderSystem.rotatef(270, 0, 0, 1); + matrices.translate(0, height, 0); + matrices.multiply(Vec3f.POSITIVE_Z.getDegreesQuaternion(270)); } - drawButton(0, 0, 0, aWidth); + drawButton(matrices, 0, 0, 0, aWidth); // 1: regular, 2: hovered, 0: disabled/dragging int thumbX = Math.round(coordToValueRatio * (value - min)); @@ -182,23 +181,23 @@ public class WLabeledSlider extends WAbstractSlider { boolean hovering = rotMouseX >= thumbX && rotMouseX <= thumbX + thumbWidth && rotMouseY >= thumbY && rotMouseY <= thumbY + thumbHeight; int thumbState = dragging || hovering ? 2 : 1; - drawButton(thumbX, thumbY, thumbState, thumbWidth); + drawButton(matrices, thumbX, thumbY, thumbState, thumbWidth); if (thumbState == 1 && isFocused()) { float px = 1 / 32f; - ScreenDrawing.texturedRect(thumbX, thumbY, thumbWidth, thumbHeight, WSlider.LIGHT_TEXTURE, 24*px, 0*px, 32*px, 20*px, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, thumbX, thumbY, thumbWidth, thumbHeight, WSlider.LIGHT_TEXTURE, 24*px, 0*px, 32*px, 20*px, 0xFFFFFFFF); } if (label != null) { int color = isMouseInsideBounds(mouseX, mouseY) ? 0xFFFFA0 : 0xE0E0E0; ScreenDrawing.drawStringWithShadow(matrices, label.asOrderedText(), labelAlignment, 2, aHeight / 2 - 4, aWidth - 4, color); } - RenderSystem.popMatrix(); + matrices.pop(); } // state = 1: regular, 2: hovered, 0: disabled/dragging @Environment(EnvType.CLIENT) - private void drawButton(int x, int y, int state, int width) { + private void drawButton(MatrixStack matrices, int x, int y, int state, int width) { float px = 1 / 256f; float buttonLeft = 0 * px; float buttonTop = (46 + (state * 20)) * px; @@ -208,8 +207,8 @@ public class WLabeledSlider extends WAbstractSlider { float buttonHeight = 20 * px; float buttonEndLeft = (200 - halfWidth) * px; - ScreenDrawing.texturedRect(x, y, halfWidth, 20, AbstractButtonWidget.WIDGETS_LOCATION, buttonLeft, buttonTop, buttonLeft + buttonWidth, buttonTop + buttonHeight, 0xFFFFFFFF); - ScreenDrawing.texturedRect(x + halfWidth, y, halfWidth, 20, AbstractButtonWidget.WIDGETS_LOCATION, buttonEndLeft, buttonTop, 200 * px, buttonTop + buttonHeight, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x, y, halfWidth, 20, AbstractButtonWidget.WIDGETS_LOCATION, buttonLeft, buttonTop, buttonLeft + buttonWidth, buttonTop + buttonHeight, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x + halfWidth, y, halfWidth, 20, AbstractButtonWidget.WIDGETS_LOCATION, buttonEndLeft, buttonTop, 200 * px, buttonTop + buttonHeight, 0xFFFFFFFF); } /** diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java index 90ef5d6..51a10ce 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WPanel.java @@ -26,15 +26,6 @@ public abstract class WPanel extends WWidget { @Environment(EnvType.CLIENT) private BackgroundPainter backgroundPainter = null; - @SuppressWarnings("deprecation") - @Override - public void createPeers(GuiDescription c) { - super.createPeers(c); - for(WWidget child : children) { - child.createPeers(c); - } - } - /** * Removes the widget from this panel. * @@ -92,70 +83,6 @@ public abstract class WPanel extends WWidget { this.setSize(Math.max(this.getWidth(), pushRight), Math.max(this.getHeight(), pushDown)); } - @Environment(EnvType.CLIENT) - @Override - public WWidget onMouseUp(int x, int y, int button) { - if (children.isEmpty()) return super.onMouseUp(x, y, button); - for(int i=children.size()-1; i>=0; i--) { //Backwards so topmost widgets get priority - WWidget child = children.get(i); - if ( x>=child.getX() && - y>=child.getY() && - x<child.getX()+child.getWidth() && - y<child.getY()+child.getHeight()) { - return child.onMouseUp(x-child.getX(), y-child.getY(), button); - } - } - return super.onMouseUp(x, y, button); - } - - @Environment(EnvType.CLIENT) - @Override - public WWidget onMouseDown(int x, int y, int button) { - if (children.isEmpty()) return super.onMouseDown(x, y, button); - for(int i=children.size()-1; i>=0; i--) { //Backwards so topmost widgets get priority - WWidget child = children.get(i); - if ( x>=child.getX() && - y>=child.getY() && - x<child.getX()+child.getWidth() && - y<child.getY()+child.getHeight()) { - return child.onMouseDown(x-child.getX(), y-child.getY(), button); - } - } - return super.onMouseDown(x, y, button); - } - - @Environment(EnvType.CLIENT) - @Override - public void onMouseDrag(int x, int y, int button) { - if (children.isEmpty()) return; - for(int i=children.size()-1; i>=0; i--) { //Backwards so topmost widgets get priority - WWidget child = children.get(i); - if ( x>=child.getX() && - y>=child.getY() && - x<child.getX()+child.getWidth() && - y<child.getY()+child.getHeight()) { - child.onMouseDrag(x-child.getX(), y-child.getY(), button); - return; //Only send the message to the first valid recipient - } - } - super.onMouseDrag(x, y, button); - } - /* - @Override - public void onClick(int x, int y, int button) { - if (children.isEmpty()) return; - for(int i=children.size()-1; i>=0; i--) { //Backwards so topmost widgets get priority - WWidget child = children.get(i); - if ( x>=child.getX() && - y>=child.getY() && - x<child.getX()+child.getWidth() && - y<child.getY()+child.getHeight()) { - child.onClick(x-child.getX(), y-child.getY(), button); - return; //Only send the message to the first valid recipient - } - } - }*/ - /** * Finds the most specific child node at this location. */ @@ -188,13 +115,12 @@ public abstract class WPanel extends WWidget { for (WWidget child : children) { child.validate(c); } - if (c!=null) createPeers(c); } @Environment(EnvType.CLIENT) @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { - if (backgroundPainter!=null) backgroundPainter.paintBackground(x, y, this); + if (backgroundPainter!=null) backgroundPainter.paintBackground(matrices, x, y, this); for(WWidget child : children) { child.paint(matrices, x + child.getX(), y + child.getY(), mouseX-child.getX(), mouseY-child.getY()); diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WScrollBar.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WScrollBar.java index 500f312..ea23953 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WScrollBar.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WScrollBar.java @@ -4,9 +4,10 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.util.math.MatrixStack; -import io.github.cottonmc.cotton.gui.client.LibGuiClient; +import io.github.cottonmc.cotton.gui.client.LibGui; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import io.github.cottonmc.cotton.gui.widget.data.Axis; +import io.github.cottonmc.cotton.gui.widget.data.InputResult; public class WScrollBar extends WWidget { protected Axis axis = Axis.HORIZONTAL; @@ -36,10 +37,10 @@ public class WScrollBar extends WWidget { @Environment(EnvType.CLIENT) @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { - if (LibGuiClient.config.darkMode) { - ScreenDrawing.drawBeveledPanel(x, y, width, height, 0xFF_212121, 0xFF_2F2F2F, 0xFF_5D5D5D); + if (LibGui.isDarkMode()) { + ScreenDrawing.drawBeveledPanel(matrices, x, y, width, height, 0xFF_212121, 0xFF_2F2F2F, 0xFF_5D5D5D); } else { - ScreenDrawing.drawBeveledPanel(x, y, width, height, 0xFF_373737, 0xFF_8B8B8B, 0xFF_FFFFFF); + ScreenDrawing.drawBeveledPanel(matrices, x, y, width, height, 0xFF_373737, 0xFF_8B8B8B, 0xFF_FFFFFF); } if (maxValue<=0) return; @@ -47,7 +48,7 @@ public class WScrollBar extends WWidget { int top, middle, bottom; if (sliding) { - if (LibGuiClient.config.darkMode) { + if (LibGui.isDarkMode()) { top = 0xFF_6C6C6C; middle = 0xFF_2F2F2F; bottom = 0xFF_212121; @@ -57,7 +58,7 @@ public class WScrollBar extends WWidget { bottom = 0xFF_555555; } } else if (isWithinBounds(mouseX, mouseY)) { - if (LibGuiClient.config.darkMode) { + if (LibGui.isDarkMode()) { top = 0xFF_5F6A9D; middle = 0xFF_323F6E; bottom = 0xFF_0B204A; @@ -67,7 +68,7 @@ public class WScrollBar extends WWidget { bottom = 0xFF_343E75; } } else { - if (LibGuiClient.config.darkMode) { + if (LibGui.isDarkMode()) { top = 0xFF_6C6C6C; middle = 0xFF_414141; bottom = 0xFF_212121; @@ -79,16 +80,16 @@ public class WScrollBar extends WWidget { } if (axis==Axis.HORIZONTAL) { - ScreenDrawing.drawBeveledPanel(x+1+getHandlePosition(), y+1, getHandleSize(), height-2, top, middle, bottom); + ScreenDrawing.drawBeveledPanel(matrices, x+1+getHandlePosition(), y+1, getHandleSize(), height-2, top, middle, bottom); if (isFocused()) { - drawBeveledOutline(x+1+getHandlePosition(), y+1, getHandleSize(), height-2, 0xFF_FFFFA7, 0xFF_8C8F39); + drawBeveledOutline(matrices, x+1+getHandlePosition(), y+1, getHandleSize(), height-2, 0xFF_FFFFA7, 0xFF_8C8F39); } } else { - ScreenDrawing.drawBeveledPanel(x+1, y+1+getHandlePosition(), width-2, getHandleSize(), top, middle, bottom); + ScreenDrawing.drawBeveledPanel(matrices, x+1, y+1+getHandlePosition(), width-2, getHandleSize(), top, middle, bottom); if (isFocused()) { - drawBeveledOutline(x+1, y+1+getHandlePosition(), width-2, getHandleSize(), 0xFF_FFFFA7, 0xFF_8C8F39); + drawBeveledOutline(matrices, x+1, y+1+getHandlePosition(), width-2, getHandleSize(), 0xFF_FFFFA7, 0xFF_8C8F39); } } } @@ -103,11 +104,12 @@ public class WScrollBar extends WWidget { return true; } - private static void drawBeveledOutline(int x, int y, int width, int height, int topleft, int bottomright) { - ScreenDrawing.coloredRect(x, y, width, 1, topleft); //Top shadow - ScreenDrawing.coloredRect(x, y + 1, 1, height - 1, topleft); //Left shadow - ScreenDrawing.coloredRect(x + width - 1, y + 1, 1, height - 1, bottomright); //Right hilight - ScreenDrawing.coloredRect(x + 1, y + height - 1, width - 1, 1, bottomright); //Bottom hilight + @Environment(EnvType.CLIENT) + private static void drawBeveledOutline(MatrixStack matrices, int x, int y, int width, int height, int topleft, int bottomright) { + ScreenDrawing.coloredRect(matrices, x, y, width, 1, topleft); //Top shadow + ScreenDrawing.coloredRect(matrices, x, y + 1, 1, height - 1, topleft); //Left shadow + ScreenDrawing.coloredRect(matrices, x + width - 1, y + 1, 1, height - 1, bottomright); //Right hilight + ScreenDrawing.coloredRect(matrices, x + 1, y + height - 1, width - 1, 1, bottomright); //Bottom hilight } /** @@ -166,7 +168,7 @@ public class WScrollBar extends WWidget { } @Override - public WWidget onMouseDown(int x, int y, int button) { + public InputResult onMouseDown(int x, int y, int button) { //TODO: Clicking before or after the handle should jump instead of scrolling requestFocus(); @@ -178,23 +180,25 @@ public class WScrollBar extends WWidget { anchorValue = value; } sliding = true; - return this; + + return InputResult.PROCESSED; } @Environment(EnvType.CLIENT) @Override - public void onMouseDrag(int x, int y, int button) { + public InputResult onMouseDrag(int x, int y, int button, double deltaX, double deltaY) { adjustSlider(x, y); + return InputResult.PROCESSED; } @Environment(EnvType.CLIENT) @Override - public WWidget onMouseUp(int x, int y, int button) { + public InputResult onMouseUp(int x, int y, int button) { //TODO: Clicking before or after the handle should jump instead of scrolling anchor = -1; anchorValue = -1; sliding = false; - return this; + return InputResult.PROCESSED; } @Override @@ -216,8 +220,9 @@ public class WScrollBar extends WWidget { @Environment(EnvType.CLIENT) @Override - public void onMouseScroll(int x, int y, double amount) { + public InputResult onMouseScroll(int x, int y, double amount) { setValue(getValue() + (int) -amount); + return InputResult.PROCESSED; } public int getValue() { diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java index 0e78333..a63c9cb 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSlider.java @@ -6,7 +6,7 @@ import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.Identifier; import io.github.cottonmc.cotton.gui.client.BackgroundPainter; -import io.github.cottonmc.cotton.gui.client.LibGuiClient; +import io.github.cottonmc.cotton.gui.client.LibGui; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import io.github.cottonmc.cotton.gui.widget.data.Axis; import org.jetbrains.annotations.Nullable; @@ -50,14 +50,14 @@ public class WSlider extends WAbstractSlider { @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { if (backgroundPainter != null) { - backgroundPainter.paintBackground(x, y, this); + backgroundPainter.paintBackground(matrices, x, y, this); } else { float px = 1 / 32f; // thumbX/Y: thumb position in widget-space int thumbX, thumbY; // thumbXOffset: thumb texture x offset in pixels int thumbXOffset; - Identifier texture = LibGuiClient.config.darkMode ? DARK_TEXTURE : LIGHT_TEXTURE; + Identifier texture = LibGui.isDarkMode() ? DARK_TEXTURE : LIGHT_TEXTURE; if (axis == Axis.VERTICAL) { int trackX = x + width / 2 - TRACK_WIDTH / 2; @@ -67,9 +67,9 @@ public class WSlider extends WAbstractSlider { : Math.round(coordToValueRatio * (value - min)); thumbXOffset = 0; - ScreenDrawing.texturedRect(trackX, y + 1, TRACK_WIDTH, 1, texture, 16*px, 0*px, 22*px, 1*px, 0xFFFFFFFF); - ScreenDrawing.texturedRect(trackX, y + 2, TRACK_WIDTH, height - 2, texture, 16*px, 1*px, 22*px, 2*px, 0xFFFFFFFF); - ScreenDrawing.texturedRect(trackX, y + height, TRACK_WIDTH, 1, texture, 16*px, 2*px, 22*px, 3*px, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, trackX, y + 1, TRACK_WIDTH, 1, texture, 16*px, 0*px, 22*px, 1*px, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, trackX, y + 2, TRACK_WIDTH, height - 2, texture, 16*px, 1*px, 22*px, 2*px, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, trackX, y + height, TRACK_WIDTH, 1, texture, 16*px, 2*px, 22*px, 3*px, 0xFFFFFFFF); } else { int trackY = y + height / 2 - TRACK_WIDTH / 2; thumbX = direction == Direction.LEFT @@ -78,18 +78,18 @@ public class WSlider extends WAbstractSlider { thumbY = height / 2 - THUMB_SIZE / 2; thumbXOffset = 8; - ScreenDrawing.texturedRect(x, trackY, 1, TRACK_WIDTH, texture, 16*px, 3*px, 17*px, 9*px, 0xFFFFFFFF); - ScreenDrawing.texturedRect(x + 1, trackY, width - 2, TRACK_WIDTH, texture, 17*px, 3*px, 18*px, 9*px, 0xFFFFFFFF); - ScreenDrawing.texturedRect(x + width - 1, trackY, 1, TRACK_WIDTH, texture, 18*px, 3*px, 19*px, 9*px, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x, trackY, 1, TRACK_WIDTH, texture, 16*px, 3*px, 17*px, 9*px, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x + 1, trackY, width - 2, TRACK_WIDTH, texture, 17*px, 3*px, 18*px, 9*px, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x + width - 1, trackY, 1, TRACK_WIDTH, texture, 18*px, 3*px, 19*px, 9*px, 0xFFFFFFFF); } // thumbState values: // 0: default, 1: dragging, 2: hovered int thumbState = dragging ? 1 : (mouseX >= thumbX && mouseX <= thumbX + THUMB_SIZE && mouseY >= thumbY && mouseY <= thumbY + THUMB_SIZE ? 2 : 0); - ScreenDrawing.texturedRect(x + thumbX, y + thumbY, THUMB_SIZE, THUMB_SIZE, texture, thumbXOffset*px, 0*px + thumbState * 8*px, (thumbXOffset + 8)*px, 8*px + thumbState * 8*px, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x + thumbX, y + thumbY, THUMB_SIZE, THUMB_SIZE, texture, thumbXOffset*px, 0*px + thumbState * 8*px, (thumbXOffset + 8)*px, 8*px + thumbState * 8*px, 0xFFFFFFFF); if (thumbState == 0 && isFocused()) { - ScreenDrawing.texturedRect(x + thumbX, y + thumbY, THUMB_SIZE, THUMB_SIZE, texture, 0*px, 24*px, 8*px, 32*px, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x + thumbX, y + thumbY, THUMB_SIZE, THUMB_SIZE, texture, 0*px, 24*px, 8*px, 32*px, 0xFFFFFFFF); } } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSprite.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSprite.java index 632ca6c..a17ed42 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WSprite.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WSprite.java @@ -184,7 +184,7 @@ public class WSprite extends WWidget { @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { if (singleImage) { - paintFrame(x, y, frames[0]); + paintFrame(matrices, x, y, frames[0]); } else { //grab the system time at the very start of the frame. long now = System.nanoTime() / 1_000_000L; @@ -194,7 +194,7 @@ public class WSprite extends WWidget { if (!inBounds) currentFrame = 0; //assemble and draw the frame calculated last iteration. Texture currentFrameTex = frames[currentFrame]; - paintFrame(x, y, currentFrameTex); + paintFrame(matrices, x, y, currentFrameTex); //calculate how much time has elapsed since the last animation change, and change the frame if necessary. long elapsed = now - lastFrame; @@ -216,12 +216,13 @@ public class WSprite extends WWidget { /** * Paints a single frame for this sprite. * - * @param x the X coordinate to draw it at - * @param y the Y coordinate to draw it at - * @param texture the texture to draw + * @param matrices the rendering matrix stack + * @param x the X coordinate to draw it at + * @param y the Y coordinate to draw it at + * @param texture the texture to draw */ @Environment(EnvType.CLIENT) - protected void paintFrame(int x, int y, Texture texture) { - ScreenDrawing.texturedRect(x, y, getWidth(), getHeight(), texture, tint); + protected void paintFrame(MatrixStack matrices, int x, int y, Texture texture) { + ScreenDrawing.texturedRect(matrices, x, y, getWidth(), getHeight(), texture, tint); } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTabPanel.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTabPanel.java index efb71d5..ae23842 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTabPanel.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTabPanel.java @@ -11,18 +11,16 @@ import net.minecraft.text.Text; import net.minecraft.util.Identifier; import io.github.cottonmc.cotton.gui.client.BackgroundPainter; -import io.github.cottonmc.cotton.gui.client.LibGuiClient; +import io.github.cottonmc.cotton.gui.client.LibGui; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; import io.github.cottonmc.cotton.gui.widget.data.Axis; import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; +import io.github.cottonmc.cotton.gui.widget.data.InputResult; +import io.github.cottonmc.cotton.gui.widget.data.Tab; import io.github.cottonmc.cotton.gui.widget.icon.Icon; -import org.jetbrains.annotations.Nullable; import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.List; -import java.util.Objects; import java.util.function.Consumer; // TODO: Different tab positions @@ -99,178 +97,6 @@ public class WTabPanel extends WPanel { mainPanel.setBackgroundPainter(BackgroundPainter.VANILLA); } - /** - * The data of a tab. - */ - public static class Tab { - @Nullable - private final Text title; - @Nullable - private final Icon icon; - private final WWidget widget; - @Nullable - private final Consumer<TooltipBuilder> tooltip; - - /** - * Constructs a tab. - * - * @param title the tab title - * @param icon the tab icon - * @param widget the widget contained in the tab - * @param tooltip the tab tooltip - * @throws IllegalArgumentException if both the title and the icon are null - * @throws NullPointerException if the widget is null - * @deprecated Use {@link Builder} instead. - */ - @Deprecated - public Tab(@Nullable Text title, @Nullable Icon icon, WWidget widget, @Nullable Consumer<TooltipBuilder> tooltip) { - if (title == null && icon == null) { - throw new IllegalArgumentException("A tab must have a title or an icon"); - } - - this.title = title; - this.icon = icon; - this.widget = Objects.requireNonNull(widget, "widget"); - this.tooltip = tooltip; - } - - /** - * Gets the title of this tab. - * - * @return the title, or null if there's no title - */ - @Nullable - public Text getTitle() { - return title; - } - - /** - * Gets the icon of this tab. - * - * @return the icon, or null if there's no title - */ - @Nullable - public Icon getIcon() { - return icon; - } - - /** - * Gets the contained widget of this tab. - * - * @return the contained widget - */ - public WWidget getWidget() { - return widget; - } - - /** - * Adds this widget's tooltip to the {@code tooltip} builder. - * - * @param tooltip the tooltip builder - */ - @Environment(EnvType.CLIENT) - public void addTooltip(TooltipBuilder tooltip) { - if (this.tooltip != null) { - this.tooltip.accept(tooltip); - } - } - - /** - * A builder for tab data. - */ - public static final class Builder { - @Nullable - private Text title; - @Nullable - private Icon icon; - private final WWidget widget; - private final List<Text> tooltip = new ArrayList<>(); - - /** - * Constructs a new tab data builder. - * - * @param widget the contained widget - * @throws NullPointerException if the widget is null - */ - public Builder(WWidget widget) { - this.widget = Objects.requireNonNull(widget, "widget"); - } - - /** - * Sets the tab title. - * - * @param title the new title - * @return this builder - * @throws NullPointerException if the title is null - */ - public Builder title(Text title) { - this.title = Objects.requireNonNull(title, "title"); - return this; - } - - /** - * Sets the tab icon. - * - * @param icon the new icon - * @return this builder - * @throws NullPointerException if the icon is null - */ - public Builder icon(Icon icon) { - this.icon = Objects.requireNonNull(icon, "icon"); - return this; - } - - /** - * Adds lines to the tab's tooltip. - * - * @param lines the added lines - * @return this builder - * @throws NullPointerException if the line array is null - */ - public Builder tooltip(Text... lines) { - Objects.requireNonNull(lines, "lines"); - Collections.addAll(tooltip, lines); - - return this; - } - - /** - * Adds lines to the tab's tooltip. - * - * @param lines the added lines - * @return this builder - * @throws NullPointerException if the line collection is null - */ - public Builder tooltip(Collection<? extends Text> lines) { - Objects.requireNonNull(lines, "lines"); - tooltip.addAll(lines); - return this; - } - - /** - * Builds a tab from this builder. - * - * @return the built tab - */ - public Tab build() { - Consumer<TooltipBuilder> tooltip = null; - - if (!this.tooltip.isEmpty()) { - //noinspection Convert2Lambda - tooltip = new Consumer<TooltipBuilder>() { - @Environment(EnvType.CLIENT) - @Override - public void accept(TooltipBuilder builder) { - builder.add(Tab.Builder.this.tooltip.toArray(new Text[0])); - } - }; - } - - return new Tab(title, icon, widget, tooltip); - } - } - } - private final class WTab extends WWidget { private final Tab data; boolean selected = false; @@ -286,9 +112,7 @@ public class WTabPanel extends WPanel { @Environment(EnvType.CLIENT) @Override - public void onClick(int x, int y, int button) { - super.onClick(x, y, button); - + public InputResult onClick(int x, int y, int button) { MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); for (WTab tab : tabWidgets) { @@ -297,6 +121,7 @@ public class WTabPanel extends WPanel { mainPanel.setSelectedCard(data.getWidget()); WTabPanel.this.layout(); + return InputResult.PROCESSED; } @Environment(EnvType.CLIENT) @@ -324,9 +149,9 @@ public class WTabPanel extends WPanel { } } - (selected ? Painters.SELECTED_TAB : Painters.UNSELECTED_TAB).paintBackground(x, y, this); + (selected ? Painters.SELECTED_TAB : Painters.UNSELECTED_TAB).paintBackground(matrices, x, y, this); if (isFocused()) { - (selected ? Painters.SELECTED_TAB_FOCUS_BORDER : Painters.UNSELECTED_TAB_FOCUS_BORDER).paintBackground(x, y, this); + (selected ? Painters.SELECTED_TAB_FOCUS_BORDER : Painters.UNSELECTED_TAB_FOCUS_BORDER).paintBackground(matrices, x, y, this); } int iconX = 6; @@ -338,7 +163,7 @@ public class WTabPanel extends WPanel { HorizontalAlignment align = (icon != null) ? HorizontalAlignment.LEFT : HorizontalAlignment.CENTER; int color; - if (LibGuiClient.config.darkMode) { + if (LibGui.isDarkMode()) { color = WLabel.DEFAULT_DARKMODE_TEXT_COLOR; } else { color = selected ? WLabel.DEFAULT_TEXT_COLOR : 0xEEEEEE; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WText.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WText.java index 953f995..6f8afca 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WText.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WText.java @@ -4,16 +4,15 @@ import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; -import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.OrderedText; import net.minecraft.text.Style; import net.minecraft.text.Text; -import io.github.cottonmc.cotton.gui.client.LibGuiClient; +import io.github.cottonmc.cotton.gui.client.LibGui; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; -import io.github.cottonmc.cotton.gui.client.TextHoverRendererScreen; import io.github.cottonmc.cotton.gui.widget.data.HorizontalAlignment; +import io.github.cottonmc.cotton.gui.widget.data.InputResult; import io.github.cottonmc.cotton.gui.widget.data.VerticalAlignment; import org.jetbrains.annotations.Nullable; @@ -109,29 +108,26 @@ public class WText extends WWidget { for (int i = 0; i < wrappedLines.size(); i++) { OrderedText line = wrappedLines.get(i); - int c = LibGuiClient.config.darkMode ? darkmodeColor : color; + int c = LibGui.isDarkMode() ? darkmodeColor : color; ScreenDrawing.drawString(matrices, line, horizontalAlignment, x, y + yOffset + i * font.fontHeight, width, c); } Style hoveredTextStyle = getTextStyleAt(mouseX, mouseY); - if (hoveredTextStyle != null) { - Screen screen = MinecraftClient.getInstance().currentScreen; - if (screen instanceof TextHoverRendererScreen) { - ((TextHoverRendererScreen) screen).renderTextHover(matrices, hoveredTextStyle, x + mouseX, y + mouseY); - } - } + ScreenDrawing.drawTextHover(matrices, hoveredTextStyle, x + mouseX, y + mouseY); } @Environment(EnvType.CLIENT) @Override - public void onClick(int x, int y, int button) { - if (button != 0) return; // only left clicks + public InputResult onClick(int x, int y, int button) { + if (button != 0) return InputResult.IGNORED; // only left clicks Style hoveredTextStyle = getTextStyleAt(x, y); if (hoveredTextStyle != null) { MinecraftClient.getInstance().currentScreen.handleTextClick(hoveredTextStyle); } + + return InputResult.PROCESSED; } /** diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java index 8ff03cf..ead273b 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTextField.java @@ -9,17 +9,19 @@ import net.minecraft.client.font.TextRenderer; import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.render.BufferBuilder; import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexFormat; import net.minecraft.client.render.VertexFormats; import net.minecraft.client.util.math.MatrixStack; import net.minecraft.text.LiteralText; import net.minecraft.text.Text; import net.minecraft.util.math.MathHelper; +import net.minecraft.util.math.Matrix4f; import io.github.cottonmc.cotton.gui.client.BackgroundPainter; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; +import io.github.cottonmc.cotton.gui.widget.data.InputResult; import org.jetbrains.annotations.Nullable; import org.lwjgl.glfw.GLFW; -import org.lwjgl.opengl.GL11; import java.util.function.Consumer; import java.util.function.Predicate; @@ -86,78 +88,6 @@ public class WTextField extends WWidget { public void setSize(int x, int y) { super.setSize(x, 20); } - - /* - public String getSelectedText() { - int start = this.cursorMax < this.cursorMin ? this.cursorMax : this.cursorMin; - int end = this.cursorMax < this.cursorMin ? this.cursorMin : this.cursorMax; - return this.text.substring(start, end); - }*/ - - /* - //This would seem to insert or paste text in the vanilla control - public void addText(String string_1) { - String string_2 = ""; - String string_3 = SharedConstants.stripInvalidChars(string_1); - int int_1 = this.cursorMax < this.cursorMin ? this.cursorMax : this.cursorMin; - int int_2 = this.cursorMax < this.cursorMin ? this.cursorMin : this.cursorMax; - int int_3 = this.maxLength - this.text.length() - (int_1 - int_2); - if (!this.text.isEmpty()) { - string_2 = string_2 + this.text.substring(0, int_1); - } - - int int_5; - if (int_3 < string_3.length()) { - string_2 = string_2 + string_3.substring(0, int_3); - int_5 = int_3; - } else { - string_2 = string_2 + string_3; - int_5 = string_3.length(); - } - - if (!this.text.isEmpty() && int_2 < this.text.length()) { - string_2 = string_2 + this.text.substring(int_2); - } - - if (this.textPredicate.test(string_2)) { - this.text = string_2; - this.setCursor(int_1 + int_5); - this.method_1884(this.cursorMax); - this.onChanged(this.text); - } - }*/ - - /* - - //this would seem to delete text. if int_1 is negative, deletes from the end? - public void method_1878(int int_1) { - if (!this.text.isEmpty()) { - if (this.cursorMin != this.cursorMax) { - this.addText(""); - } else { - boolean boolean_1 = int_1 < 0; - int int_2 = boolean_1 ? this.cursorMax + int_1 : this.cursorMax; - int int_3 = boolean_1 ? this.cursorMax : this.cursorMax + int_1; - String string_1 = ""; - if (int_2 >= 0) { - string_1 = this.text.substring(0, int_2); - } - - if (int_3 < this.text.length()) { - string_1 = string_1 + this.text.substring(int_3); - } - - if (this.textPredicate.test(string_1)) { - this.text = string_1; - if (boolean_1) { - this.moveCursor(int_1); - } - - this.onChanged(this.text); - } - } - } - }*/ public void setCursorPos(int location) { this.cursor = MathHelper.clamp(location, 0, this.text.length()); @@ -190,132 +120,14 @@ public class WTextField extends WWidget { public boolean isEditable() { return this.editable; } - - /* - public boolean keyPressed(int int_1, int int_2, int int_3) { - if (!this.method_20315()) { - return false; - } else { - this.field_17037 = Screen.hasShiftDown(); - if (Screen.isSelectAll(int_1)) { - this.method_1872(); - this.method_1884(0); - return true; - } else if (Screen.isCopy(int_1)) { - MinecraftClient.getInstance().keyboard.setClipboard(this.getSelectedText()); - return true; - } else if (Screen.isPaste(int_1)) { - if (this.editable) { - this.addText(MinecraftClient.getInstance().keyboard.getClipboard()); - } - - return true; - } else if (Screen.isCut(int_1)) { - MinecraftClient.getInstance().keyboard.setClipboard(this.getSelectedText()); - if (this.editable) { - this.addText(""); - } - - return true; - } else { - switch(int_1) { - case 259: - if (this.editable) { - this.method_16873(-1); - } - - return true; - case 260: - case 264: - case 265: - case 266: - case 267: - default: - return false; - case 261: - if (this.editable) { - this.method_16873(1); - } - - return true; - case 262: - if (Screen.hasControlDown()) { - this.method_1883(this.method_1853(1)); - } else { - this.moveCursor(1); - } - - return true; - case 263: - if (Screen.hasControlDown()) { - this.method_1883(this.method_1853(-1)); - } else { - this.moveCursor(-1); - } - - return true; - case 268: - this.method_1870(); - return true; - case 269: - this.method_1872(); - return true; - } - } - } - }*/ - - /* - public boolean charTyped(char char_1, int int_1) { - if (!this.method_20315()) { - return false; - } else if (SharedConstants.isValidChar(char_1)) { - if (this.editable) { - this.addText(Character.toString(char_1)); - } - - return true; - } else { - return false; - } - }*/ - /* - @Override - public void onClick(int x, int y, int button) { - - } - - public boolean mouseClicked(double double_1, double double_2, int int_1) { - if (!this.isVisible()) { - return false; - } else { - boolean boolean_1 = double_1 >= (double)this.x && double_1 < (double)(this.x + this.width) && double_2 >= (double)this.y && double_2 < (double)(this.y + this.height); - if (this.field_2096) { - this.method_1876(boolean_1); - } - - if (this.isFocused() && boolean_1 && int_1 == 0) { - int int_2 = MathHelper.floor(double_1) - this.x; - if (this.focused) { - int_2 -= 4; - } - - String string_1 = this.textRenderer.trimToWidth(this.text.substring(this.field_2103), this.method_1859()); - this.method_1883(this.textRenderer.trimToWidth(string_1, int_2).length() + this.field_2103); - return true; - } else { - return false; - } - } - }*/ @Environment(EnvType.CLIENT) protected void renderTextField(MatrixStack matrices, int x, int y) { if (this.font==null) this.font = MinecraftClient.getInstance().textRenderer; int borderColor = (this.isFocused()) ? 0xFF_FFFFA0 : 0xFF_A0A0A0; - ScreenDrawing.coloredRect(x-1, y-1, width+2, height+2, borderColor); - ScreenDrawing.coloredRect(x, y, width, height, 0xFF000000); + ScreenDrawing.coloredRect(matrices, x-1, y-1, width+2, height+2, borderColor); + ScreenDrawing.coloredRect(matrices, x, y, width, height, 0xFF000000); int textColor = this.editable ? this.enabledColor : this.uneditableColor; @@ -369,7 +181,7 @@ public class WTextField extends WWidget { //} else { // caretLoc = textX+caretLoc-1; //} - ScreenDrawing.coloredRect(preCursorAdvance-1, textY-2, 1, 12, 0xFFD0D0D0); + ScreenDrawing.coloredRect(matrices, preCursorAdvance-1, textY-2, 1, 12, 0xFFD0D0D0); //if (boolean_3) { // int var10001 = int_7 - 1; // var10002 = int_9 + 1; @@ -390,7 +202,7 @@ public class WTextField extends WWidget { b = a; a = tmp; } - invertedRect(textX+a-1, textY-1, Math.min(b-a, width - OFFSET_X_TEXT), 12); + invertedRect(matrices, textX+a-1, textY-1, Math.min(b-a, width - OFFSET_X_TEXT), 12); // int int_10 = int_6 + MinecraftClient.getInstance().textRenderer.getStringWidth(trimText.substring(0, adjustedCursor)); // var10002 = int_7 - 1; // var10003 = int_10 - 1; @@ -400,18 +212,18 @@ public class WTextField extends WWidget { } @Environment(EnvType.CLIENT) - private void invertedRect(int x, int y, int width, int height) { + private void invertedRect(MatrixStack matrices, int x, int y, int width, int height) { Tessellator tessellator_1 = Tessellator.getInstance(); BufferBuilder bufferBuilder_1 = tessellator_1.getBuffer(); - RenderSystem.color4f(0.0F, 0.0F, 255.0F, 255.0F); + Matrix4f model = matrices.peek().getModel(); RenderSystem.disableTexture(); RenderSystem.enableColorLogicOp(); RenderSystem.logicOp(GlStateManager.LogicOp.OR_REVERSE); - bufferBuilder_1.begin(GL11.GL_QUADS, VertexFormats.POSITION); - bufferBuilder_1.vertex(x, y+height, 0.0D).next(); - bufferBuilder_1.vertex(x+width, y+height, 0.0D).next(); - bufferBuilder_1.vertex(x+width, y, 0.0D).next(); - bufferBuilder_1.vertex(x, y, 0.0D).next(); + bufferBuilder_1.begin(VertexFormat.DrawMode.QUADS, VertexFormats.POSITION_COLOR); + bufferBuilder_1.vertex(model, x, y+height, 0).color(0, 0, 255, 255).next(); + bufferBuilder_1.vertex(model, x+width, y+height, 0).color(0, 0, 255, 255).next(); + bufferBuilder_1.vertex(model, x+width, y, 0).color(0, 0, 255, 255).next(); + bufferBuilder_1.vertex(model, x, y, 0).color(0, 0, 255, 255).next(); tessellator_1.draw(); RenderSystem.disableColorLogicOp(); RenderSystem.enableTexture(); @@ -538,9 +350,10 @@ public class WTextField extends WWidget { @Environment(EnvType.CLIENT) @Override - public void onClick(int x, int y, int button) { + public InputResult onClick(int x, int y, int button) { requestFocus(); cursor = getCaretPos(this.text, x-OFFSET_X_TEXT); + return InputResult.PROCESSED; } @Environment(EnvType.CLIENT) @@ -655,6 +468,7 @@ public class WTextField extends WWidget { } } else { if (modifiers==GLFW.GLFW_MOD_SHIFT) { + // TODO: Add Ctrl word selection support if (ch==GLFW.GLFW_KEY_LEFT) { if (select==-1) select = cursor; if (cursor>0) cursor--; diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTiledSprite.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTiledSprite.java index 5750636..0ab9d7c 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WTiledSprite.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WTiledSprite.java @@ -2,6 +2,7 @@ package io.github.cottonmc.cotton.gui.widget; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; +import net.minecraft.client.util.math.MatrixStack; import net.minecraft.util.Identifier; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; @@ -129,13 +130,14 @@ public class WTiledSprite extends WSprite { @Environment(EnvType.CLIENT) @Override - public void paintFrame(int x, int y, Texture texture) { + public void paintFrame(MatrixStack matrices, int x, int y, Texture texture) { // Y Direction (down) for (int tileYOffset = 0; tileYOffset < height; tileYOffset += tileHeight) { // X Direction (right) for (int tileXOffset = 0; tileXOffset < width; tileXOffset += tileWidth) { // draw the texture ScreenDrawing.texturedRect( + matrices, // at the correct position using tileXOffset and tileYOffset x + tileXOffset, y + tileYOffset, // but using the set tileWidth and tileHeight instead of the full height and diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WToggleButton.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WToggleButton.java index 1142928..355572e 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WToggleButton.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WToggleButton.java @@ -9,8 +9,9 @@ import net.minecraft.sound.SoundEvents; import net.minecraft.text.Text; import net.minecraft.util.Identifier; -import io.github.cottonmc.cotton.gui.client.LibGuiClient; +import io.github.cottonmc.cotton.gui.client.LibGui; import io.github.cottonmc.cotton.gui.client.ScreenDrawing; +import io.github.cottonmc.cotton.gui.widget.data.InputResult; import io.github.cottonmc.cotton.gui.widget.data.Texture; import org.jetbrains.annotations.Nullable; @@ -101,13 +102,13 @@ public class WToggleButton extends WWidget { @Environment(EnvType.CLIENT) @Override public void paint(MatrixStack matrices, int x, int y, int mouseX, int mouseY) { - ScreenDrawing.texturedRect(x, y, 18, 18, isOn ? onImage : offImage, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x, y, 18, 18, isOn ? onImage : offImage, 0xFFFFFFFF); if (isFocused()) { - ScreenDrawing.texturedRect(x, y, 18, 18, focusImage, 0xFFFFFFFF); + ScreenDrawing.texturedRect(matrices, x, y, 18, 18, focusImage, 0xFFFFFFFF); } if (label!=null) { - ScreenDrawing.drawString(matrices, label.asOrderedText(), x + 22, y+6, LibGuiClient.config.darkMode ? darkmodeColor : color); + ScreenDrawing.drawString(matrices, label.asOrderedText(), x + 22, y+6, LibGui.isDarkMode() ? darkmodeColor : color); } } @@ -123,13 +124,14 @@ public class WToggleButton extends WWidget { @Environment(EnvType.CLIENT) @Override - public void onClick(int x, int y, int button) { + public InputResult onClick(int x, int y, int button) { super.onClick(x, y, button); MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F)); this.isOn = !this.isOn; onToggle(this.isOn); + return InputResult.PROCESSED; } @Override diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java index cd3c31b..f78723b 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/WWidget.java @@ -3,11 +3,12 @@ package io.github.cottonmc.cotton.gui.widget; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.MinecraftClient; -import net.minecraft.client.gui.screen.Screen; import net.minecraft.client.util.math.MatrixStack; import com.google.common.annotations.Beta; import io.github.cottonmc.cotton.gui.GuiDescription; +import io.github.cottonmc.cotton.gui.impl.access.ScreenAccessor; +import io.github.cottonmc.cotton.gui.widget.data.InputResult; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; @@ -153,17 +154,16 @@ public class WWidget { * @param x The X coordinate of the event, in widget-space (0 is the left edge of this widget) * @param y The Y coordinate of the event, in widget-space (0 is the top edge of this widget) * @param button The mouse button that was used. Button numbering is consistent with LWJGL Mouse (0=left, 1=right, 2=mousewheel click) + * @return {@link InputResult#PROCESSED} if the event is handled, {@link InputResult#IGNORED} otherwise. */ @Environment(EnvType.CLIENT) - public WWidget onMouseDown(int x, int y, int button) { - return this; + public InputResult onMouseDown(int x, int y, int button) { + return InputResult.IGNORED; } /** * Notifies this widget that the mouse has been moved while pressed and inside its bounds. * - * <p>The default implementation calls {@link #onMouseDrag(int, int, int)} for backwards compatibility. - * * @param x The X coordinate of the event, in widget-space (0 is the left edge of this widget) * @param y The Y coordinate of the event, in widget-space (0 is the top edge of this widget) * @param button The mouse button that was used. Button numbering is consistent with LWJGL Mouse (0=left, 1=right, 2=mousewheel click) @@ -171,20 +171,11 @@ public class WWidget { * @param deltaY The amount of dragging on the Y axis * * @since 1.5.0 + * @return {@link InputResult#PROCESSED} if the event is handled, {@link InputResult#IGNORED} otherwise. */ @Environment(EnvType.CLIENT) - public void onMouseDrag(int x, int y, int button, double deltaX, double deltaY) { - onMouseDrag(x, y, button); - } - - /** - * Notifies this widget that the mouse has been moved while pressed and inside its bounds - * @param x The X coordinate of the event, in widget-space (0 is the left edge of this widget) - * @param y The Y coordinate of the event, in widget-space (0 is the top edge of this widget) - * @param button The mouse button that was used. Button numbering is consistent with LWJGL Mouse (0=left, 1=right, 2=mousewheel click) - */ - @Environment(EnvType.CLIENT) - public void onMouseDrag(int x, int y, int button) { + public InputResult onMouseDrag(int x, int y, int button, double deltaX, double deltaY) { + return InputResult.IGNORED; } /** @@ -192,10 +183,11 @@ public class WWidget { * @param x The X coordinate of the event, in widget-space (0 is the left edge of this widget) * @param y The Y coordinate of the event, in widget-space (0 is the top edge of this widget) * @param button The mouse button that was used. Button numbering is consistent with LWJGL Mouse (0=left, 1=right, 2=mousewheel click) + * @return {@link InputResult#PROCESSED} if the event is handled, {@link InputResult#IGNORED} otherwise. */ @Environment(EnvType.CLIENT) - public WWidget onMouseUp(int x, int y, int button) { - return this; + public InputResult onMouseUp(int x, int y, int button) { + return InputResult.IGNORED; } /** @@ -203,9 +195,11 @@ public class WWidget { * @param x The X coordinate of the event, in widget-space (0 is the left edge of this widget) * @param y The Y coordinate of the event, in widget-space (0 is the top edge of this widget) * @param button The mouse button that was used. Button numbering is consistent with LWJGL Mouse (0=left, 1=right, 2=mousewheel click) + * @return {@link InputResult#PROCESSED} if the event is handled, {@link InputResult#IGNORED} otherwise. */ @Environment(EnvType.CLIENT) - public void onClick(int x, int y, int button) { + public InputResult onClick(int x, int y, int button) { + return InputResult.IGNORED; } /** @@ -213,9 +207,11 @@ public class WWidget { * @param x The X coordinate of the event, in widget-space (0 is the left edge of this widget) * @param y The Y coordinate of the event, in widget-space (0 is the top edge of this widget) * @param amount The scrolled amount. Positive values are up and negative values are down. + * @return {@link InputResult#PROCESSED} if the event is handled, {@link InputResult#IGNORED} otherwise. */ @Environment(EnvType.CLIENT) - public void onMouseScroll(int x, int y, double amount) { + public InputResult onMouseScroll(int x, int y, double amount) { + return InputResult.IGNORED; } /** @@ -224,9 +220,11 @@ public class WWidget { * @param x The X coordinate of the event, in widget-space (0 is the left edge of this widget) * @param y The Y coordinate of the event, in widget-space (0 is the top edge of this widget) * @since 1.5.0 + * @return {@link InputResult#PROCESSED} if the event is handled, {@link InputResult#IGNORED} otherwise. */ @Environment(EnvType.CLIENT) - public void onMouseMove(int x, int y) { + public InputResult onMouseMove(int x, int y) { + return InputResult.IGNORED; } /** @@ -305,15 +303,6 @@ public class WWidget { } /** - * Creates "heavyweight" component peers - * @param c the top-level Container that will hold the peers - * @deprecated All widget peers should be added in {@link #validate(GuiDescription)}. - */ - @Deprecated - public void createPeers(GuiDescription c) { - } - - /** * Paints this widget. * * @param matrices the rendering matrix stack @@ -356,8 +345,8 @@ public class WWidget { if (builder.size() == 0) return; - Screen screen = MinecraftClient.getInstance().currentScreen; - screen.renderOrderedTooltip(matrices, builder.lines, tX+x, tY+y); + ScreenAccessor screen = (ScreenAccessor) MinecraftClient.getInstance().currentScreen; + screen.callRenderTooltipFromComponents(matrices, builder.components, tX+x, tY+y); } /** @@ -370,7 +359,7 @@ public class WWidget { if (host != null) { this.host = host; } else { - LOGGER.warn("Validating {} with a null host", this); + LOGGER.warn("Validating {} with a null host", this); } } diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/data/InputResult.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/InputResult.java new file mode 100644 index 0000000..991cfd3 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/InputResult.java @@ -0,0 +1,12 @@ +package io.github.cottonmc.cotton.gui.widget.data; + +/** + * Specifies whether an input event was ignored or processed. + * Used for mouse input events. + * + * @since 4.0.0 + */ +public enum InputResult { + PROCESSED, + IGNORED; +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/data/Tab.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/Tab.java new file mode 100644 index 0000000..05f6933 --- /dev/null +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/data/Tab.java @@ -0,0 +1,189 @@ +package io.github.cottonmc.cotton.gui.widget.data; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.text.Text; + +import io.github.cottonmc.cotton.gui.widget.TooltipBuilder; +import io.github.cottonmc.cotton.gui.widget.WWidget; +import io.github.cottonmc.cotton.gui.widget.icon.Icon; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.function.Consumer; + +/** + * The data of a tab. + * + * @see io.github.cottonmc.cotton.gui.widget.WTabPanel + */ +public final class Tab { + @Nullable + private final Text title; + @Nullable + private final Icon icon; + private final WWidget widget; + @Nullable + private final Consumer<TooltipBuilder> tooltip; + + /** + * Constructs a tab. + * + * @param title the tab title + * @param icon the tab icon + * @param widget the widget contained in the tab + * @param tooltip the tab tooltip + * @throws IllegalArgumentException if both the title and the icon are null + * @throws NullPointerException if the widget is null + */ + private Tab(@Nullable Text title, @Nullable Icon icon, WWidget widget, @Nullable Consumer<TooltipBuilder> tooltip) { + if (title == null && icon == null) { + throw new IllegalArgumentException("A tab must have a title or an icon"); + } + + this.title = title; + this.icon = icon; + this.widget = Objects.requireNonNull(widget, "widget"); + this.tooltip = tooltip; + } + + /** + * Gets the title of this tab. + * + * @return the title, or null if there's no title + */ + @Nullable + public Text getTitle() { + return title; + } + + /** + * Gets the icon of this tab. + * + * @return the icon, or null if there's no title + */ + @Nullable + public Icon getIcon() { + return icon; + } + + /** + * Gets the contained widget of this tab. + * + * @return the contained widget + */ + public WWidget getWidget() { + return widget; + } + + /** + * Adds this widget's tooltip to the {@code tooltip} builder. + * + * @param tooltip the tooltip builder + */ + @Environment(EnvType.CLIENT) + public void addTooltip(TooltipBuilder tooltip) { + if (this.tooltip != null) { + this.tooltip.accept(tooltip); + } + } + + /** + * A builder for tab data. + */ + public static final class Builder { + @Nullable + private Text title; + @Nullable + private Icon icon; + private final WWidget widget; + private final List<Text> tooltip = new ArrayList<>(); + + /** + * Constructs a new tab data builder. + * + * @param widget the contained widget + * @throws NullPointerException if the widget is null + */ + public Builder(WWidget widget) { + this.widget = Objects.requireNonNull(widget, "widget"); + } + + /** + * Sets the tab title. + * + * @param title the new title + * @return this builder + * @throws NullPointerException if the title is null + */ + public Builder title(Text title) { + this.title = Objects.requireNonNull(title, "title"); + return this; + } + + /** + * Sets the tab icon. + * + * @param icon the new icon + * @return this builder + * @throws NullPointerException if the icon is null + */ + public Builder icon(Icon icon) { + this.icon = Objects.requireNonNull(icon, "icon"); + return this; + } + + /** + * Adds lines to the tab's tooltip. + * + * @param lines the added lines + * @return this builder + * @throws NullPointerException if the line array is null + */ + public Builder tooltip(Text... lines) { + Objects.requireNonNull(lines, "lines"); + Collections.addAll(tooltip, lines); + + return this; + } + + /** + * Adds lines to the tab's tooltip. + * + * @param lines the added lines + * @return this builder + * @throws NullPointerException if the line collection is null + */ + public Builder tooltip(Collection<? extends Text> lines) { + Objects.requireNonNull(lines, "lines"); + tooltip.addAll(lines); + return this; + } + + /** + * Builds a tab from this builder. + * + * @return the built tab + */ + public Tab build() { + Consumer<TooltipBuilder> tooltip = null; + + if (!this.tooltip.isEmpty()) { + //noinspection Convert2Lambda + tooltip = new Consumer<TooltipBuilder>() { + @Environment(EnvType.CLIENT) + @Override + public void accept(TooltipBuilder builder) { + builder.add(Builder.this.tooltip.toArray(new Text[0])); + } + }; + } + + return new Tab(title, icon, widget, tooltip); + } + } +} diff --git a/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/TextureIcon.java b/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/TextureIcon.java index 18cf4c3..acc3ce5 100644 --- a/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/TextureIcon.java +++ b/src/main/java/io/github/cottonmc/cotton/gui/widget/icon/TextureIcon.java @@ -80,6 +80,6 @@ public class TextureIcon implements Icon { @Environment(EnvType.CLIENT) @Override public void paint(MatrixStack matrices, int x, int y, int size) { - ScreenDrawing.texturedRect(x, y, size, size, texture, color, opacity); + ScreenDrawing.texturedRect(matrices, x, y, size, size, texture, color, opacity); } } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index b540edf..ca3cde8 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -19,8 +19,8 @@ "environment": "*", "entrypoints": { "main": ["io.github.cottonmc.cotton.gui.impl.LibGuiCommon"], - "client": ["io.github.cottonmc.cotton.gui.client.LibGuiClient"], - "modmenu": ["io.github.cottonmc.cotton.gui.client.modmenu.ModMenuSupport"] + "client": ["io.github.cottonmc.cotton.gui.impl.client.LibGuiClient"], + "modmenu": ["io.github.cottonmc.cotton.gui.impl.client.modmenu.ModMenuSupport"] }, "mixins": [ "mixins.libgui.accessors.json" diff --git a/src/main/resources/mixins.libgui.accessors.json b/src/main/resources/mixins.libgui.accessors.json index 9ec55f2..03d0946 100644 --- a/src/main/resources/mixins.libgui.accessors.json +++ b/src/main/resources/mixins.libgui.accessors.json @@ -5,6 +5,7 @@ "required": true, "mixins": [ + "ScreenAccessor", "SlotAccessor" ], |