From 97f788ecd4be15b1556ee1f3d8bd057bdf06bf5f Mon Sep 17 00:00:00 2001 From: DeDiamondPro <67508414+DeDiamondPro@users.noreply.github.com> Date: Wed, 17 Aug 2022 17:43:23 +0200 Subject: Input revamp (#93) * hud fix * api * things * stuff --- .../cc/polyfrost/oneconfig/utils/InputHandler.java | 215 +++++++++++++++++++++ .../cc/polyfrost/oneconfig/utils/InputUtils.java | 195 ------------------- .../cc/polyfrost/oneconfig/utils/gui/GuiUtils.java | 10 + .../polyfrost/oneconfig/utils/gui/OneUIScreen.java | 97 +++------- 4 files changed, 250 insertions(+), 267 deletions(-) create mode 100644 src/main/java/cc/polyfrost/oneconfig/utils/InputHandler.java delete mode 100644 src/main/java/cc/polyfrost/oneconfig/utils/InputUtils.java (limited to 'src/main/java/cc/polyfrost/oneconfig/utils') diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/InputHandler.java b/src/main/java/cc/polyfrost/oneconfig/utils/InputHandler.java new file mode 100644 index 0000000..6bd8207 --- /dev/null +++ b/src/main/java/cc/polyfrost/oneconfig/utils/InputHandler.java @@ -0,0 +1,215 @@ +/* + * This file is part of OneConfig. + * OneConfig - Next Generation Config Library for Minecraft: Java Edition + * Copyright (C) 2021, 2022 Polyfrost. + * + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * OneConfig is licensed under the terms of version 3 of the GNU Lesser + * General Public License as published by the Free Software Foundation, AND + * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, + * either version 1.0 of the Additional Terms, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License. If not, see . You should + * have also received a copy of the Additional Terms Applicable + * to OneConfig, as published by Polyfrost. If not, see + * + */ + +package cc.polyfrost.oneconfig.utils; + +import cc.polyfrost.oneconfig.libs.universal.UResolution; +import cc.polyfrost.oneconfig.platform.Platform; +import cc.polyfrost.oneconfig.renderer.scissor.Scissor; +import cc.polyfrost.oneconfig.utils.gui.GuiUtils; + +import java.util.ArrayList; + +/** + * Various utility methods for input. + *

+ * All values returned from this class are not scaled to Minecraft's GUI scale. + * For scaled values, see {@link cc.polyfrost.oneconfig.libs.universal.UMouse}. + *

+ */ +public class InputHandler { + private final ArrayList blockScissors = new ArrayList<>(); + private double scaleX = 1d; + private double scaleY = 1d; + + /** + * Push a scale for the input utils to use + * + * @param scaleX X scale + * @param scaleY Y scale + */ + public void scale(double scaleX, double scaleY) { + this.scaleX = scaleX; + this.scaleY = scaleY; + } + + /** + * Reset the scale input utils uses + */ + public void resetScale() { + scaleX = 1d; + scaleY = 1d; + } + + + /** + * function to determine weather the mouse is currently over a specific region. Uses the current nvgScale to fix to any scale. + * + * @return true if mouse is over region, false if not. + */ + public boolean isAreaHovered(float x, float y, float width, float height, boolean ignoreBlock) { + float mouseX = mouseX(); + float mouseY = mouseY(); + return (ignoreBlock || blockScissors.size() == 0 || !shouldBlock(mouseX, mouseY)) && mouseX > x && mouseY > y && mouseX < x + width && mouseY < y + height; + } + + /** + * function to determine weather the mouse is currently over a specific region. Uses the current nvgScale to fix to any scale. + * + * @return true if mouse is over region, false if not. + */ + public boolean isAreaHovered(float x, float y, float width, float height) { + return isAreaHovered(x, y, width, height, false); + } + + /** + * Checks whether the mouse is currently over a specific region and clicked. + * + * @param x the x position of the region + * @param y the y position of the region + * @param width the width of the region + * @param height the height of the region + * @param ignoreBlock if true, will ignore + * @return true if the mouse is clicked and is over the region, false if not + * @see InputHandler#isAreaHovered(float, float, float, float) + */ + public boolean isAreaClicked(float x, float y, float width, float height, boolean ignoreBlock) { + return isAreaHovered(x, y, width, height, ignoreBlock) && isClicked(false); + } + + /** + * Checks whether the mouse is currently over a specific region and clicked. + * + * @param x the x position of the region + * @param y the y position of the region + * @param width the width of the region + * @param height the height of the region + * @return true if the mouse is clicked and is over the region, false if not + * @see InputHandler#isAreaClicked(float, float, float, float, boolean) + */ + public boolean isAreaClicked(float x, float y, float width, float height) { + return isAreaClicked(x, y, width, height, false); + } + + /** + * Checks whether the mouse is clicked or not. + * + * @param ignoreBlock if true, will ignore + * @return true if the mouse is clicked, false if not + */ + public boolean isClicked(boolean ignoreBlock) { + return GuiUtils.wasMouseDown() && !Platform.getMousePlatform().isButtonDown(0) && (ignoreBlock || blockScissors.size() == 0 || !shouldBlock(mouseX(), mouseY())); + } + + /** + * Checks whether the mouse is clicked or not. + * + * @return true if the mouse is clicked, false if not + * @see InputHandler#isClicked(boolean) + */ + public boolean isClicked() { + return isClicked(false); + } + + /** + * Gets the current mouse X position. + *

+ * All values returned from this class are not scaled to Minecraft's GUI scale. + * For scaled values, see {@link cc.polyfrost.oneconfig.libs.universal.UMouse}. + *

+ * + * @return the current mouse X position + */ + public float mouseX() { + return (float) (Platform.getMousePlatform().getMouseX() / scaleX); + } + + /** + * Gets the current mouse Y position. + *

+ * All values returned from this class are not scaled to Minecraft's GUI scale. + * For scaled values, see {@link cc.polyfrost.oneconfig.libs.universal.UMouse}. + *

+ * + * @return the current mouse Y position + */ + public float mouseY() { + return (float) ((UResolution.getWindowHeight() - Math.abs(Platform.getMousePlatform().getMouseY())) / scaleY); + } + + /** + * Block all clicks outside an area + * + * @param x X coordinate + * @param y Y coordinate + * @param width Width + * @param height Height + */ + public Scissor blockInputArea(float x, float y, float width, float height) { + Scissor scissor = new Scissor(new Scissor(x, y, width, height)); + blockScissors.add(scissor); + return scissor; + } + + /** + * Should be used if there is something above other components and you don't want it clicking trough + */ + public Scissor blockAllInput() { + return blockInputArea(0, 0, 1920, 1080); + } + + /** + * Stop blocking an area from being interacted with + * + * @param scissor The scissor area + */ + public void stopBlock(Scissor scissor) { + blockScissors.remove(scissor); + } + + /** + * Clears all blocking areas + */ + public void stopBlockingInput() { + blockScissors.clear(); + } + + /** + * Whether clicks are blocked + * + * @return true if clicks are blocked, false if not + */ + public boolean isBlockingInput() { + return blockScissors.size() > 0; + } + + private boolean shouldBlock(float x, float y) { + for (Scissor block : blockScissors) { + if (block.isInScissor(x, y)) return true; + } + return false; + } +} diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/InputUtils.java b/src/main/java/cc/polyfrost/oneconfig/utils/InputUtils.java deleted file mode 100644 index 3fb32f7..0000000 --- a/src/main/java/cc/polyfrost/oneconfig/utils/InputUtils.java +++ /dev/null @@ -1,195 +0,0 @@ -/* - * This file is part of OneConfig. - * OneConfig - Next Generation Config Library for Minecraft: Java Edition - * Copyright (C) 2021, 2022 Polyfrost. - * - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * OneConfig is licensed under the terms of version 3 of the GNU Lesser - * General Public License as published by the Free Software Foundation, AND - * under the Additional Terms Applicable to OneConfig, as published by Polyfrost, - * either version 1.0 of the Additional Terms, or (at your option) any later - * version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License. If not, see . You should - * have also received a copy of the Additional Terms Applicable - * to OneConfig, as published by Polyfrost. If not, see - * - */ - -package cc.polyfrost.oneconfig.utils; - -import cc.polyfrost.oneconfig.gui.OneConfigGui; -import cc.polyfrost.oneconfig.libs.universal.UResolution; -import cc.polyfrost.oneconfig.platform.Platform; -import cc.polyfrost.oneconfig.renderer.scissor.Scissor; - -import java.util.ArrayList; - -/** - * Various utility methods for input. - *

- * All values returned from this class are not scaled to Minecraft's GUI scale. - * For scaled values, see {@link cc.polyfrost.oneconfig.libs.universal.UMouse}. - *

- */ -public final class InputUtils { - private static final ArrayList blockScissors = new ArrayList<>(); - - /** - * function to determine weather the mouse is currently over a specific region. Uses the current nvgScale to fix to any scale. - * - * @return true if mouse is over region, false if not. - */ - public static boolean isAreaHovered(float x, float y, float width, float height, boolean ignoreBlock) { - float mouseX = mouseX(); - float mouseY = mouseY(); - return (ignoreBlock || blockScissors.size() == 0 || !shouldBlock(mouseX, mouseY)) && mouseX > x && mouseY > y && mouseX < x + width && mouseY < y + height; - } - - /** - * function to determine weather the mouse is currently over a specific region. Uses the current nvgScale to fix to any scale. - * - * @return true if mouse is over region, false if not. - */ - public static boolean isAreaHovered(float x, float y, float width, float height) { - return isAreaHovered(x, y, width, height, false); - } - - /** - * Checks whether the mouse is currently over a specific region and clicked. - * - * @param x the x position of the region - * @param y the y position of the region - * @param width the width of the region - * @param height the height of the region - * @param ignoreBlock if true, will ignore - * @return true if the mouse is clicked and is over the region, false if not - * @see InputUtils#isAreaHovered(float, float, float, float) - */ - public static boolean isAreaClicked(float x, float y, float width, float height, boolean ignoreBlock) { - return isAreaHovered(x, y, width, height, ignoreBlock) && isClicked(false); - } - - /** - * Checks whether the mouse is currently over a specific region and clicked. - * - * @param x the x position of the region - * @param y the y position of the region - * @param width the width of the region - * @param height the height of the region - * @return true if the mouse is clicked and is over the region, false if not - * @see InputUtils#isAreaClicked(float, float, float, float, boolean) - */ - public static boolean isAreaClicked(float x, float y, float width, float height) { - return isAreaClicked(x, y, width, height, false); - } - - /** - * Checks whether the mouse is clicked or not. - * - * @param ignoreBlock if true, will ignore - * @return true if the mouse is clicked, false if not - */ - public static boolean isClicked(boolean ignoreBlock) { - return OneConfigGui.INSTANCE != null && OneConfigGui.INSTANCE.mouseDown && !Platform.getMousePlatform().isButtonDown(0) && (ignoreBlock || blockScissors.size() == 0 || !shouldBlock(mouseX(), mouseY())); - } - - /** - * Checks whether the mouse is clicked or not. - * - * @return true if the mouse is clicked, false if not - * @see InputUtils#isClicked(boolean) - */ - public static boolean isClicked() { - return isClicked(false); - } - - /** - * Gets the current mouse X position. - *

- * All values returned from this class are not scaled to Minecraft's GUI scale. - * For scaled values, see {@link cc.polyfrost.oneconfig.libs.universal.UMouse}. - *

- * - * @return the current mouse X position - */ - public static float mouseX() { - if (OneConfigGui.INSTANCE == null) return (float) Platform.getMousePlatform().getMouseX(); - return (float) (Platform.getMousePlatform().getMouseX() / OneConfigGui.INSTANCE.getScaleFactor()); - } - - /** - * Gets the current mouse Y position. - *

- * All values returned from this class are not scaled to Minecraft's GUI scale. - * For scaled values, see {@link cc.polyfrost.oneconfig.libs.universal.UMouse}. - *

- * - * @return the current mouse Y position - */ - public static float mouseY() { - if (OneConfigGui.INSTANCE == null) return (float) (UResolution.getWindowHeight() - Math.abs(Platform.getMousePlatform().getMouseY())); - return (float) ((UResolution.getWindowHeight() - Math.abs(Platform.getMousePlatform().getMouseY())) / OneConfigGui.INSTANCE.getScaleFactor()); - } - - /** - * Block all clicks outside an area - * - * @param x X coordinate - * @param y Y coordinate - * @param width Width - * @param height Height - */ - public static Scissor blockInputArea(float x, float y, float width, float height) { - Scissor scissor = new Scissor(new Scissor(x, y, width, height)); - blockScissors.add(scissor); - return scissor; - } - - /** - * Should be used if there is something above other components and you don't want it clicking trough - */ - public static Scissor blockAllInput() { - return blockInputArea(0, 0, 1920, 1080); - } - - /** - * Stop blocking an area from being interacted with - * - * @param scissor The scissor area - */ - public static void stopBlock(Scissor scissor) { - blockScissors.remove(scissor); - } - - /** - * Clears all blocking areas - */ - public static void stopBlockingInput() { - blockScissors.clear(); - } - - /** - * Whether clicks are blocked - * - * @return true if clicks are blocked, false if not - */ - public static boolean isBlockingInput() { - return blockScissors.size() > 0; - } - - private static boolean shouldBlock(float x, float y) { - for (Scissor block : blockScissors) { - if (block.isInScissor(x, y)) return true; - } - return false; - } -} diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/gui/GuiUtils.java b/src/main/java/cc/polyfrost/oneconfig/utils/gui/GuiUtils.java index e3dffb6..71bba26 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/gui/GuiUtils.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/gui/GuiUtils.java @@ -41,6 +41,7 @@ import cc.polyfrost.oneconfig.utils.TickDelay; public final class GuiUtils { private static long time = -1L; private static long deltaTime = 17L; + private static boolean wasMouseDown = false; static { EventManager.INSTANCE.register(new GuiUtils()); @@ -86,6 +87,13 @@ public final class GuiUtils { return deltaTime; } + /** + * @return If the mouse was down last frame + */ + public static boolean wasMouseDown() { + return wasMouseDown; + } + @Subscribe private void onRenderEvent(RenderEvent event) { if (event.stage == Stage.START) { @@ -95,6 +103,8 @@ public final class GuiUtils { deltaTime = currentTime - time; time = currentTime; } + } else if (event.stage == Stage.END) { + wasMouseDown = Platform.getMousePlatform().isButtonDown(0); } } } diff --git a/src/main/java/cc/polyfrost/oneconfig/utils/gui/OneUIScreen.java b/src/main/java/cc/polyfrost/oneconfig/utils/gui/OneUIScreen.java index 5f93c7b..45242b2 100644 --- a/src/main/java/cc/polyfrost/oneconfig/utils/gui/OneUIScreen.java +++ b/src/main/java/cc/polyfrost/oneconfig/utils/gui/OneUIScreen.java @@ -28,115 +28,68 @@ package cc.polyfrost.oneconfig.utils.gui; import cc.polyfrost.oneconfig.gui.GuiPause; import cc.polyfrost.oneconfig.libs.universal.UMatrixStack; +import cc.polyfrost.oneconfig.libs.universal.UResolution; import cc.polyfrost.oneconfig.libs.universal.UScreen; -import cc.polyfrost.oneconfig.platform.Platform; import cc.polyfrost.oneconfig.renderer.RenderManager; -import cc.polyfrost.oneconfig.utils.InputUtils; +import cc.polyfrost.oneconfig.utils.InputHandler; import org.jetbrains.annotations.NotNull; /** *

OneUIScreen

* OneUIScreen is a GUI that can be used to render things on the client's screen. - * It contains many handy methods for rendering, including {@link #draw(long, float)} for drawing using OneConfig's {@link RenderManager}. - *

It also contains methods for mouse input. (see {@link InputUtils} for more utils). + * It contains many handy methods for rendering, including {@link #draw(long, float, InputHandler)} for drawing using OneConfig's {@link RenderManager}. + *

It also contains methods for mouse input. (see {@link InputHandler} for more utils). *

* Use GuiUtils to display a screen; and GuiUtils.closeScreen to close it. */ public abstract class OneUIScreen extends UScreen implements GuiPause { - private boolean mouseDown; - private boolean blockClicks; + private final boolean useMinecraftScale; + private final InputHandler inputHandler = new InputHandler(); /** * Create a new OneUIScreen. * + * @param useMinecraftScale wether to use Minecraft scale * @param restoreGuiOnClose use this to declare weather or not to open the Gui that was open before it when this screen is closed. */ - public OneUIScreen(boolean restoreGuiOnClose) { + public OneUIScreen(boolean useMinecraftScale, boolean restoreGuiOnClose) { super(restoreGuiOnClose); + this.useMinecraftScale = useMinecraftScale; + } + + /** + * Create a new OneUIScreen. + * + * @param useMinecraftScale wether to use Minecraft scale + */ + public OneUIScreen(boolean useMinecraftScale) { + this(useMinecraftScale, false); } /** * Create a new OneUIScreen. */ public OneUIScreen() { - super(false); + this(false, false); } @Override public final void onDrawScreen(@NotNull UMatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { super.onDrawScreen(matrixStack, mouseX, mouseY, partialTicks); - RenderManager.setupAndDraw(ignoreMinecraftScale(), vg -> draw(vg, partialTicks)); - mouseDown = Platform.getMousePlatform().isButtonDown(0); + if (useMinecraftScale) inputHandler.scale(UResolution.getScaleFactor(), UResolution.getScaleFactor()); + RenderManager.setupAndDraw(useMinecraftScale, vg -> draw(vg, partialTicks, inputHandler)); } - /** * Use this method to draw things on the screen. It is called every render tick, and has a handy vg (NanoVG context) that can be used with the {@link RenderManager} to draw things. *

* For example: {@link RenderManager#drawRoundedRect(long, float, float, float, float, int, float)} * - * @param vg the NanoVG context you can use to render things with - * @param partialTicks the time between ticks (You can use this as a deltaTime equivalent) - */ - public abstract void draw(long vg, float partialTicks); - - /** - * Use this method to set whether to use the Minecraft scale on the GUI. Its default is true, and that is recommended for the NanoVG rendering. - */ - public boolean ignoreMinecraftScale() { - return true; - } - - /** - * Get the current x position of the mouse. - */ - protected float getMouseX() { - return InputUtils.mouseX(); - } - - /** - * Get the current y position of the mouse. - */ - protected float getMouseY() { - return InputUtils.mouseY(); - } - - /** - * Retrieve the click status of the mouse. This method uses a boolean to store the status of the mouse, so it will only return true once per click. (very useful) - * - * @param ignoreBlockClicks whether to ignore the current click blocker. - */ - protected boolean isClicked(boolean ignoreBlockClicks) { - return mouseDown && !Platform.getMousePlatform().isButtonDown(0) && (!blockClicks || ignoreBlockClicks); - } - - /** - * Retrieve the click status of the mouse. This method uses a boolean to store the status of the mouse, so it will only return true once per click. (very useful) - */ - protected boolean isClicked() { - return isClicked(false); - } - - /** - * Retrieve weather or not the mouse is currently down. Will constantly return true if its clicked. See {@link #isClicked()} for a method that only executes once per tick. - */ - protected boolean isMouseDown() { - return Platform.getMousePlatform().isButtonDown(0); - } - - /** - * Click blocking can be useful when you are drawing buttons for example over the top of other elements, so a click blocker can be used to ensure that the mouse doesn't click through things. + * @param vg The NanoVG context you can use to render things with + * @param partialTicks The time between ticks (You can use this as a deltaTime equivalent) + * @param inputHandler The input handler */ - public void shouldBlockClicks(boolean state) { - blockClicks = state; - } - - /** - * Click blocking can be useful when you are drawing buttons for example over the top of other elements, so a click blocker can be used to ensure that the mouse doesn't click through things. - */ - public boolean isBlockingClicks() { - return blockClicks; - } + public abstract void draw(long vg, float partialTicks, InputHandler inputHandler); @Override public boolean doesGuiPauseGame() { -- cgit