diff options
author | ThatGravyBoat <thatgravyboat@gmail.com> | 2021-07-06 15:10:29 -0230 |
---|---|---|
committer | ThatGravyBoat <thatgravyboat@gmail.com> | 2021-07-06 15:10:29 -0230 |
commit | 6d8e1e5659f64a4f9ba86d6ab5bbc8e688faf22a (patch) | |
tree | 7451e53ceeae3c324d83a7faba83ce80005e6f23 /src/main/java/com/thatgravyboat/skyblockhud/core | |
download | skyblockhud-6d8e1e5659f64a4f9ba86d6ab5bbc8e688faf22a.tar.gz skyblockhud-6d8e1e5659f64a4f9ba86d6ab5bbc8e688faf22a.tar.bz2 skyblockhud-6d8e1e5659f64a4f9ba86d6ab5bbc8e688faf22a.zip |
Initial Commit
Diffstat (limited to 'src/main/java/com/thatgravyboat/skyblockhud/core')
41 files changed, 3994 insertions, 0 deletions
diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/BackgroundBlur.java b/src/main/java/com/thatgravyboat/skyblockhud/core/BackgroundBlur.java new file mode 100644 index 0000000..6782052 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/BackgroundBlur.java @@ -0,0 +1,231 @@ +package com.thatgravyboat.skyblockhud.core; + +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.shader.Framebuffer; +import net.minecraft.client.shader.Shader; +import net.minecraft.util.Matrix4f; +import net.minecraftforge.client.event.EntityViewRenderEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.lwjgl.opengl.GL11; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +public class BackgroundBlur { + + private static HashMap<Float, Framebuffer> blurOutput = new HashMap<>(); + private static HashMap<Float, Long> lastBlurUse = new HashMap<>(); + private static long lastBlur = 0; + private static HashSet<Float> requestedBlurs = new HashSet<>(); + + private static int fogColour = 0; + private static boolean registered = false; + public static void registerListener() { + if(!registered) { + registered = true; + MinecraftForge.EVENT_BUS.register(new BackgroundBlur()); + } + } + + private static boolean shouldBlur = true; + + public static void markDirty() { + if(Minecraft.getMinecraft().theWorld != null) { + shouldBlur = true; + } + } + + public static void processBlurs() { + if(shouldBlur) { + shouldBlur = false; + + long currentTime = System.currentTimeMillis(); + + for(float blur : requestedBlurs) { + lastBlur = currentTime; + lastBlurUse.put(blur, currentTime); + + int width = Minecraft.getMinecraft().displayWidth; + int height = Minecraft.getMinecraft().displayHeight; + + Framebuffer output = blurOutput.computeIfAbsent(blur, k -> { + Framebuffer fb = new Framebuffer(width, height, false); + fb.setFramebufferFilter(GL11.GL_NEAREST); + return fb; + }); + + output.framebufferWidth = output.framebufferTextureWidth = width; + output.framebufferHeight = output.framebufferTextureHeight = height; + + blurBackground(output, blur); + } + + Set<Float> remove = new HashSet<>(); + for(Map.Entry<Float, Long> entry : lastBlurUse.entrySet()) { + if(currentTime - entry.getValue() > 30*1000) { + remove.add(entry.getKey()); + } + } + remove.remove(5f); + + lastBlurUse.keySet().removeAll(remove); + blurOutput.keySet().removeAll(remove); + + requestedBlurs.clear(); + } + } + + @SubscribeEvent(priority = EventPriority.HIGHEST) + public void onScreenRender(RenderGameOverlayEvent.Pre event) { + if(event.type == RenderGameOverlayEvent.ElementType.ALL) { + processBlurs(); + } + } + + @SubscribeEvent + public void onFogColour(EntityViewRenderEvent.FogColors event) { + fogColour = 0xff000000; + fogColour |= ((int)(event.red*255) & 0xFF) << 16; + fogColour |= ((int)(event.green*255) & 0xFF) << 8; + fogColour |= (int)(event.blue*255) & 0xFF; + } + + private static Shader blurShaderHorz = null; + private static Shader blurShaderVert = null; + private static Framebuffer blurOutputHorz = null; + + /** + * Creates a projection matrix that projects from our coordinate space [0->width; 0->height] to OpenGL coordinate + * space [-1 -> 1; 1 -> -1] (Note: flipped y-axis). + * + * This is so that we can render to and from the framebuffer in a way that is familiar to us, instead of needing to + * apply scales and translations manually. + */ + private static Matrix4f createProjectionMatrix(int width, int height) { + Matrix4f projMatrix = new Matrix4f(); + projMatrix.setIdentity(); + projMatrix.m00 = 2.0F / (float)width; + projMatrix.m11 = 2.0F / (float)(-height); + projMatrix.m22 = -0.0020001999F; + projMatrix.m33 = 1.0F; + projMatrix.m03 = -1.0F; + projMatrix.m13 = 1.0F; + projMatrix.m23 = -1.0001999F; + return projMatrix; + } + + private static void blurBackground(Framebuffer output, float blurFactor) { + if(!OpenGlHelper.isFramebufferEnabled() || !OpenGlHelper.areShadersSupported()) return; + + int width = Minecraft.getMinecraft().displayWidth; + int height = Minecraft.getMinecraft().displayHeight; + + GlStateManager.matrixMode(GL11.GL_PROJECTION); + GlStateManager.loadIdentity(); + GlStateManager.ortho(0.0D, width, height, 0.0D, 1000.0D, 3000.0D); + GlStateManager.matrixMode(GL11.GL_MODELVIEW); + GlStateManager.loadIdentity(); + GlStateManager.translate(0.0F, 0.0F, -2000.0F); + + if(blurOutputHorz == null) { + blurOutputHorz = new Framebuffer(width, height, false); + blurOutputHorz.setFramebufferFilter(GL11.GL_NEAREST); + } + if(blurOutputHorz == null || output == null) { + return; + } + if(blurOutputHorz.framebufferWidth != width || blurOutputHorz.framebufferHeight != height) { + blurOutputHorz.createBindFramebuffer(width, height); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + + try { + blurShaderHorz = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + Minecraft.getMinecraft().getFramebuffer(), blurOutputHorz); + blurShaderHorz.getShaderManager().getShaderUniform("BlurDir").set(1, 0); + blurShaderHorz.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception ignored) { } + try { + blurShaderVert = new Shader(Minecraft.getMinecraft().getResourceManager(), "blur", + blurOutputHorz, output); + blurShaderVert.getShaderManager().getShaderUniform("BlurDir").set(0, 1); + blurShaderVert.setProjectionMatrix(createProjectionMatrix(width, height)); + } catch(Exception ignored) { } + if(blurShaderHorz != null && blurShaderVert != null) { + if(blurShaderHorz.getShaderManager().getShaderUniform("Radius") == null) { + //Corrupted shader? + return; + } + + blurShaderHorz.getShaderManager().getShaderUniform("Radius").set(blurFactor); + blurShaderVert.getShaderManager().getShaderUniform("Radius").set(blurFactor); + + GL11.glPushMatrix(); + /*GL30.glBindFramebuffer(GL30.GL_READ_FRAMEBUFFER, Minecraft.getMinecraft().getFramebuffer().framebufferObject); + GL30.glBindFramebuffer(GL30.GL_DRAW_FRAMEBUFFER, output.framebufferObject); + GL30.glBlitFramebuffer(0, 0, width, height, + 0, 0, output.framebufferWidth, output.framebufferHeight, + GL11.GL_COLOR_BUFFER_BIT, GL11.GL_NEAREST);*/ + + blurShaderHorz.loadShader(0); + blurShaderVert.loadShader(0); + GlStateManager.enableDepth(); + GL11.glPopMatrix(); + + Minecraft.getMinecraft().getFramebuffer().bindFramebuffer(false); + } + } + + public static void renderBlurredBackground(float blurStrength, int screenWidth, int screenHeight, + int x, int y, int blurWidth, int blurHeight) { + renderBlurredBackground(blurStrength, screenWidth, screenHeight, x, y, blurWidth, blurHeight, false); + } + + /** + * Renders a subsection of the blurred framebuffer on to the corresponding section of the screen. + * Essentially, this method will "blur" the background inside the bounds specified by [x->x+blurWidth, y->y+blurHeight] + */ + public static void renderBlurredBackground(float blurStrength, int screenWidth, int screenHeight, + int x, int y, int blurWidth, int blurHeight, boolean forcedUpdate) { + if(!OpenGlHelper.isFramebufferEnabled() || !OpenGlHelper.areShadersSupported()) return; + if(blurStrength < 0.5) return; + requestedBlurs.add(blurStrength); + + long currentTime = System.currentTimeMillis(); + if(currentTime - lastBlur > 300) { + shouldBlur = true; + if(currentTime - lastBlur > 400 && forcedUpdate) return; + } + + if(blurOutput.isEmpty()) return; + + Framebuffer fb = blurOutput.get(blurStrength); + if(fb == null) { + fb = blurOutput.values().iterator().next(); + } + + float uMin = x/(float)screenWidth; + float uMax = (x+blurWidth)/(float)screenWidth; + float vMin = (screenHeight-y)/(float)screenHeight; + float vMax = (screenHeight-y-blurHeight)/(float)screenHeight; + + GlStateManager.depthMask(false); + Gui.drawRect(x, y, x+blurWidth, y+blurHeight, fogColour); + fb.bindFramebufferTexture(); + GlStateManager.color(1f, 1f, 1f, 1f); + RenderUtils.drawTexturedRect(x, y, blurWidth, blurHeight, uMin, uMax, vMin, vMax); + fb.unbindFramebufferTexture(); + GlStateManager.depthMask(true); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/ChromaColour.java b/src/main/java/com/thatgravyboat/skyblockhud/core/ChromaColour.java new file mode 100644 index 0000000..b9f4e79 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/ChromaColour.java @@ -0,0 +1,95 @@ +package com.thatgravyboat.skyblockhud.core; + +import java.awt.*; + +public class ChromaColour { + + public static String special(int chromaSpeed, int alpha, int rgb) { + return special(chromaSpeed, alpha, (rgb & 0xFF0000) >> 16, (rgb & 0x00FF00) >> 8, (rgb & 0x0000FF)); + } + + private static final int RADIX = 10; + + public static String special(int chromaSpeed, int alpha, int r, int g, int b) { + StringBuilder sb = new StringBuilder(); + sb.append(Integer.toString(chromaSpeed, RADIX)).append(":"); + sb.append(Integer.toString(alpha, RADIX)).append(":"); + sb.append(Integer.toString(r, RADIX)).append(":"); + sb.append(Integer.toString(g, RADIX)).append(":"); + sb.append(Integer.toString(b, RADIX)); + return sb.toString(); + } + + private static int[] decompose(String csv) { + String[] split = csv.split(":"); + + int[] arr = new int[split.length]; + + + for(int i=0; i<split.length; i++) { + arr[i] = Integer.parseInt(split[split.length-1-i], RADIX); + } + return arr; + } + + public static int specialToSimpleRGB(String special) { + int[] d = decompose(special); + int r = d[2]; + int g = d[1]; + int b = d[0]; + int a = d[3]; + int chr = d[4]; + + return (a & 0xFF) << 24 | (r & 0xFF) << 16 | (g & 0xFF) << 8 | (b & 0xFF); + } + + public static int getSpeed(String special) { + return decompose(special)[4]; + } + + public static float getSecondsForSpeed(int speed) { + return (255-speed)/254f*(MAX_CHROMA_SECS-MIN_CHROMA_SECS)+MIN_CHROMA_SECS; + } + + private static final int MIN_CHROMA_SECS = 1; + private static final int MAX_CHROMA_SECS = 60; + + public static long startTime = -1; + public static int specialToChromaRGB(String special) { + if(startTime < 0) startTime = System.currentTimeMillis(); + + int[] d = decompose(special); + int chr = d[4]; + int a = d[3]; + int r = d[2]; + int g = d[1]; + int b = d[0]; + + float[] hsv = Color.RGBtoHSB(r, g, b, null); + + if(chr > 0) { + float seconds = getSecondsForSpeed(chr); + hsv[0] += (System.currentTimeMillis()-startTime)/1000f/seconds; + hsv[0] %= 1; + if(hsv[0] < 0) hsv[0] += 1; + } + + return (a & 0xFF) << 24 | (Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]) & 0x00FFFFFF); + } + + public static int rotateHue(int argb, int degrees) { + int a = (argb >> 24) & 0xFF; + int r = (argb >> 16) & 0xFF; + int g = (argb >> 8) & 0xFF; + int b = (argb) & 0xFF; + + float[] hsv = Color.RGBtoHSB(r, g, b, null); + + hsv[0] += degrees/360f; + hsv[0] %= 1; + + return (a & 0xFF) << 24 | (Color.HSBtoRGB(hsv[0], hsv[1], hsv[2]) & 0x00FFFFFF); + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GlScissorStack.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GlScissorStack.java new file mode 100644 index 0000000..6f21e9a --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GlScissorStack.java @@ -0,0 +1,87 @@ +package com.thatgravyboat.skyblockhud.core; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import org.lwjgl.opengl.GL11; + +import java.util.LinkedList; + +public class GlScissorStack { + + private static class Bounds { + int left; + int top; + int right; + int bottom; + + public Bounds(int left, int top, int right, int bottom) { + this.left = left; + this.top = top; + this.right = right; + this.bottom = bottom; + } + + public Bounds createSubBound(int left, int top, int right, int bottom) { + left = Math.max(left, this.left); + top = Math.max(top, this.top); + right = Math.min(right, this.right); + bottom = Math.min(bottom, this.bottom); + + if(top > bottom) { + top = bottom; + } + if(left > right) { + left = right; + } + + return new Bounds(left, top, right, bottom); + } + + public void set(ScaledResolution scaledResolution) { + int height = Minecraft.getMinecraft().displayHeight; + int scale = scaledResolution.getScaleFactor(); + GL11.glScissor(left*scale, height-bottom*scale, (right-left)*scale, (bottom-top)*scale); + } + } + + private static final LinkedList<Bounds> boundsStack = new LinkedList<>(); + + public static void push(int left, int top, int right, int bottom, ScaledResolution scaledResolution) { + if(right < left) { + int temp = right; + right = left; + left = temp; + } + if(bottom < top) { + int temp = bottom; + bottom = top; + top = temp; + } + if(boundsStack.isEmpty()) { + boundsStack.push(new Bounds(left, top, right, bottom)); + } else { + boundsStack.push(boundsStack.peek().createSubBound(left, top, right, bottom)); + } + if(!boundsStack.isEmpty()) { + boundsStack.peek().set(scaledResolution); + } + GL11.glEnable(GL11.GL_SCISSOR_TEST); + } + + public static void pop(ScaledResolution scaledResolution) { + if(!boundsStack.isEmpty()) { + boundsStack.pop(); + } + if(boundsStack.isEmpty()) { + GL11.glDisable(GL11.GL_SCISSOR_TEST); + } else { + boundsStack.peek().set(scaledResolution); + } + } + + public static void clear() { + boundsStack.clear(); + GL11.glDisable(GL11.GL_SCISSOR_TEST); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElement.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElement.java new file mode 100644 index 0000000..94d2375 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElement.java @@ -0,0 +1,8 @@ +package com.thatgravyboat.skyblockhud.core; + +public abstract class GuiElement { + + public abstract void render(); + public abstract boolean mouseInput(int mouseX, int mouseY); + public abstract boolean keyboardInput(); +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementBoolean.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementBoolean.java new file mode 100644 index 0000000..d403bef --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementBoolean.java @@ -0,0 +1,121 @@ +package com.thatgravyboat.skyblockhud.core; + +import com.thatgravyboat.skyblockhud.core.util.lerp.LerpUtils; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.GuiTextures; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Mouse; + +import java.util.function.Consumer; + +public class GuiElementBoolean extends GuiElement { + + public int x; + public int y; + private boolean value; + private int clickRadius; + private Consumer<Boolean> toggleCallback; + + private boolean previewValue; + private int animation = 0; + private long lastMillis = 0; + + private static final int xSize = 48; + private static final int ySize = 14; + + public GuiElementBoolean(int x, int y, boolean value, Consumer<Boolean> toggleCallback) { + this(x, y, value, 0, toggleCallback); + } + + public GuiElementBoolean(int x, int y, boolean value, int clickRadius, Consumer<Boolean> toggleCallback) { + this.x = x; + this.y = y; + this.value = value; + this.previewValue = value; + this.clickRadius = clickRadius; + this.toggleCallback = toggleCallback; + this.lastMillis = System.currentTimeMillis(); + + if(value) animation = 36; + } + + @Override + public void render() { + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(GuiTextures.BAR); + RenderUtils.drawTexturedRect(x, y, xSize, ySize); + + ResourceLocation buttonLoc = GuiTextures.ON; + long currentMillis = System.currentTimeMillis(); + long deltaMillis = currentMillis - lastMillis; + lastMillis = currentMillis; + boolean passedLimit = false; + if(previewValue != value) { + if((previewValue && animation > 12) || + (!previewValue && animation < 24)) { + passedLimit = true; + } + } + if(previewValue != passedLimit) { + animation += deltaMillis/10; + } else { + animation -= deltaMillis/10; + } + lastMillis -= deltaMillis%10; + + if(previewValue == value) { + animation = Math.max(0, Math.min(36, animation)); + } else if(!passedLimit) { + if(previewValue) { + animation = Math.max(0, Math.min(12, animation)); + } else { + animation = Math.max(24, Math.min(36, animation)); + } + } else { + if(previewValue) { + animation = Math.max(12, animation); + } else { + animation = Math.min(24, animation); + } + } + + int animation = (int)(LerpUtils.sigmoidZeroOne(this.animation/36f)*36); + if(animation < 3) { + buttonLoc = GuiTextures.OFF; + } else if(animation < 13) { + buttonLoc = GuiTextures.ONE; + } else if(animation < 23) { + buttonLoc = GuiTextures.TWO; + } else if(animation < 33) { + buttonLoc = GuiTextures.THREE; + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(buttonLoc); + RenderUtils.drawTexturedRect(x+animation, y, 12, 14); + } + + @Override + public boolean mouseInput(int mouseX, int mouseY) { + if(mouseX > x-clickRadius && mouseX < x+xSize+clickRadius && + mouseY > y-clickRadius && mouseY < y+ySize+clickRadius) { + if(Mouse.getEventButton() == 0) { + if(Mouse.getEventButtonState()) { + previewValue = !value; + } else if(previewValue == !value) { + value = !value; + toggleCallback.accept(value); + } + } + } else { + previewValue = value; + } + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementColour.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementColour.java new file mode 100644 index 0000000..8774595 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementColour.java @@ -0,0 +1,368 @@ +package com.thatgravyboat.skyblockhud.core; + +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.awt.*; +import java.awt.image.BufferedImage; +import java.util.function.Consumer; + +public class GuiElementColour extends GuiElement { + + public static final ResourceLocation colour_selector_dot = new ResourceLocation("skyblockhud:core/colour_selector_dot.png"); + public static final ResourceLocation colour_selector_bar = new ResourceLocation("skyblockhud:core/colour_selector_bar.png"); + public static final ResourceLocation colour_selector_bar_alpha = new ResourceLocation("skyblockhud:core/colour_selector_bar_alpha.png"); + public static final ResourceLocation colour_selector_chroma = new ResourceLocation("skyblockhud:core/colour_selector_chroma.png"); + + private static final ResourceLocation colourPickerLocation = new ResourceLocation("mbcore:dynamic/colourpicker"); + private static final ResourceLocation colourPickerBarValueLocation = new ResourceLocation("mbcore:dynamic/colourpickervalue"); + private static final ResourceLocation colourPickerBarOpacityLocation = new ResourceLocation("mbcore:dynamic/colourpickeropacity"); + private final GuiElementTextField hexField = new GuiElementTextField("", + GuiElementTextField.SCALE_TEXT | GuiElementTextField.FORCE_CAPS | GuiElementTextField.NO_SPACE); + + private int x; + private int y; + private final int xSize = 119; + private final int ySize = 89; + + private float wheelAngle = 0; + private float wheelRadius = 0; + + private int clickedComponent = -1; + + private Consumer<String> colourChangedCallback; + private Runnable closeCallback; + private String colour; + + public GuiElementColour(int x, int y, String initialColour, Consumer<String> colourChangedCallback, + Runnable closeCallback) { + + final ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + + this.y = Math.max(10, Math.min(scaledResolution.getScaledHeight()-ySize-10, y)); + this.x = Math.max(10, Math.min(scaledResolution.getScaledWidth()-xSize-10, x)); + + this.colour = initialColour; + this.colourChangedCallback = colourChangedCallback; + this.closeCallback = closeCallback; + + int colour = ChromaColour.specialToSimpleRGB(initialColour); + Color c = new Color(colour); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + updateAngleAndRadius(hsv); + } + + public void updateAngleAndRadius(float[] hsv) { + this.wheelRadius = hsv[1]; + this.wheelAngle = hsv[0]*360; + } + + public void render() { + RenderUtils.drawFloatingRectDark(x, y, xSize, ySize); + + int currentColour = ChromaColour.specialToSimpleRGB(colour); + Color c = new Color(currentColour, true); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + + BufferedImage bufferedImage = new BufferedImage(288, 288, BufferedImage.TYPE_INT_ARGB); + float borderRadius = 0.05f; + if(Keyboard.isKeyDown(Keyboard.KEY_N)) borderRadius = 0; + for(int x=-16; x<272; x++) { + for(int y=-16; y<272; y++) { + float radius = (float) Math.sqrt(((x-128)*(x-128)+(y-128)*(y-128))/16384f); + float angle = (float) Math.toDegrees(Math.atan((128-x)/(y-128+1E-5))+Math.PI/2); + if(y < 128) angle += 180; + if(radius <= 1) { + int rgb = Color.getHSBColor(angle/360f, (float)Math.pow(radius, 1.5f), hsv[2]).getRGB(); + bufferedImage.setRGB(x+16, y+16, rgb); + } else if(radius <= 1+borderRadius) { + float invBlackAlpha = Math.abs(radius-1-borderRadius/2)/borderRadius*2; + float blackAlpha = 1-invBlackAlpha; + + if(radius > 1+borderRadius/2) { + bufferedImage.setRGB(x+16, y+16, (int)(blackAlpha*255) << 24); + } else { + Color col = Color.getHSBColor(angle/360f, 1, hsv[2]); + int rgb = (int)(col.getRed()*invBlackAlpha) << 16 | + (int)(col.getGreen()*invBlackAlpha) << 8 | + (int)(col.getBlue()*invBlackAlpha); + bufferedImage.setRGB(x+16, y+16, 0xff000000 | rgb); + } + + } + } + } + + BufferedImage bufferedImageValue = new BufferedImage(10, 64, BufferedImage.TYPE_INT_ARGB); + for(int x=0; x<10; x++) { + for(int y=0; y<64; y++) { + if((x == 0 || x == 9) && (y == 0 || y == 63)) continue; + + int rgb = Color.getHSBColor(wheelAngle/360, wheelRadius, (64-y)/64f).getRGB(); + bufferedImageValue.setRGB(x, y, rgb); + } + } + + BufferedImage bufferedImageOpacity = new BufferedImage(10, 64, BufferedImage.TYPE_INT_ARGB); + for(int x=0; x<10; x++) { + for(int y=0; y<64; y++) { + if((x == 0 || x == 9) && (y == 0 || y == 63)) continue; + + int rgb = (currentColour & 0x00FFFFFF) | (Math.min(255, (64-y)*4) << 24); + bufferedImageOpacity.setRGB(x, y, rgb); + } + } + + float selradius = (float)Math.pow(wheelRadius, 1/1.5f)*32; + int selx = (int)(Math.cos(Math.toRadians(wheelAngle))*selradius); + int sely = (int)(Math.sin(Math.toRadians(wheelAngle))*selradius); + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_bar_alpha); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+5+64+5+10+5, y+5, 10, 64, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerBarValueLocation, new DynamicTexture(bufferedImageValue)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerBarValueLocation); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+5+64+5, y+5, 10, 64, GL11.GL_NEAREST); + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerBarOpacityLocation, new DynamicTexture(bufferedImageOpacity)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerBarOpacityLocation); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+5+64+5+10+5, y+5, 10, 64, GL11.GL_NEAREST); + + int chromaSpeed = ChromaColour.getSpeed(colour); + int currentColourChroma = ChromaColour.specialToChromaRGB(colour); + Color cChroma = new Color(currentColourChroma, true); + float hsvChroma[] = Color.RGBtoHSB(cChroma.getRed(), cChroma.getGreen(), cChroma.getBlue(), null); + + if(chromaSpeed > 0) { + Gui.drawRect(x+5+64+5+10+5+10+5+1, y+5+1, + x+5+64+5+10+5+10+5+10-1, y+5+64-1, + Color.HSBtoRGB(hsvChroma[0], 0.8f, 0.8f)); + } else { + Gui.drawRect(x+5+64+5+10+5+10+5+1, y+5+27+1, + x+5+64+5+10+5+10+5+10-1, y+5+37-1, + Color.HSBtoRGB((hsvChroma[0]+(System.currentTimeMillis()-ChromaColour.startTime)/1000f)%1, 0.8f, 0.8f)); + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_bar); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+5+64+5, y+5, 10, 64, GL11.GL_NEAREST); + RenderUtils.drawTexturedRect(x+5+64+5+10+5, y+5, 10, 64, GL11.GL_NEAREST); + + if(chromaSpeed > 0) { + RenderUtils.drawTexturedRect(x+5+64+5+10+5+10+5, y+5, 10, 64, GL11.GL_NEAREST); + } else { + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_chroma); + RenderUtils.drawTexturedRect(x+5+64+5+10+5+10+5, y+5+27, 10, 10, GL11.GL_NEAREST); + } + + Gui.drawRect(x+5+64+5, y+5+64-(int)(64*hsv[2]), + x+5+64+5+10, y+5+64-(int)(64*hsv[2])+1, 0xFF000000); + Gui.drawRect(x+5+64+5+10+5, y+5+64-c.getAlpha()/4, + x+5+64+5+10+5+10, y+5+64-c.getAlpha()/4-1, 0xFF000000); + if(chromaSpeed > 0) { + Gui.drawRect(x+5+64+5+10+5+10+5, + y+5+64-(int)(chromaSpeed/255f*64), + x+5+64+5+10+5+10+5+10, + y+5+64-(int)(chromaSpeed/255f*64)+1, 0xFF000000); + } + + Minecraft.getMinecraft().getTextureManager().loadTexture(colourPickerLocation, new DynamicTexture(bufferedImage)); + Minecraft.getMinecraft().getTextureManager().bindTexture(colourPickerLocation); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+1, y+1, 72, 72, GL11.GL_LINEAR); + + Minecraft.getMinecraft().getTextureManager().bindTexture(colour_selector_dot); + GlStateManager.color(1, 1, 1, 1); + RenderUtils.drawTexturedRect(x+5+32+selx-4, y+5+32+sely-4, 8, 8, GL11.GL_NEAREST); + + TextRenderUtils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+Math.round(hsv[2]*100)+"", + Minecraft.getMinecraft().fontRendererObj, + x+5+64+5+5-(Math.round(hsv[2]*100)==100?1:0), y+5+64+5+5, true, 13, -1); + TextRenderUtils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+Math.round(c.getAlpha()/255f*100)+"", + Minecraft.getMinecraft().fontRendererObj, + x+5+64+5+15+5, y+5+64+5+5, true, 13, -1); + if(chromaSpeed > 0) { + TextRenderUtils.drawStringCenteredScaledMaxWidth(EnumChatFormatting.GRAY.toString()+ + (int)ChromaColour.getSecondsForSpeed(chromaSpeed)+"s", + Minecraft.getMinecraft().fontRendererObj, + x+5+64+5+30+6, y+5+64+5+5, true, 13, -1); + } + + hexField.setSize(48, 10); + if(!hexField.getFocus()) hexField.setText(Integer.toHexString(c.getRGB() & 0xFFFFFF).toUpperCase()); + + StringBuilder sb = new StringBuilder(EnumChatFormatting.GRAY+"#"); + for(int i=0; i<6-hexField.getText().length(); i++) { + sb.append("0"); + } + sb.append(EnumChatFormatting.WHITE); + + hexField.setPrependText(sb.toString()); + hexField.render(x+5+8, y+5+64+5); + } + + public boolean mouseInput(int mouseX, int mouseY) { + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + float mouseXF = (float)(Mouse.getX() * scaledResolution.getScaledWidth_double() / + Minecraft.getMinecraft().displayWidth); + float mouseYF = (float)(scaledResolution.getScaledHeight_double() - Mouse.getY() * + scaledResolution.getScaledHeight_double() / Minecraft.getMinecraft().displayHeight - 1); + + if((Mouse.getEventButton() == 0 || Mouse.getEventButton() == 1) && Mouse.getEventButtonState()) { + if(mouseX > x+5+8 && mouseX < x+5+8+48) { + if(mouseY > y+5+64+5 && mouseY < y+5+64+5+10) { + hexField.mouseClicked(mouseX, mouseY, Mouse.getEventButton()); + clickedComponent = -1; + return true; + } + } + } + if(!Mouse.getEventButtonState() && Mouse.getEventButton() == 0) { + clickedComponent = -1; + } + if(Mouse.getEventButtonState() && Mouse.getEventButton() == 0) { + if(mouseX >= x && mouseX <= x+119 && + mouseY >= y && mouseY <= y+89) { + hexField.unfocus(); + + int xWheel = mouseX - x - 5; + int yWheel = mouseY - y - 5; + + if(xWheel > 0 && xWheel < 64) { + if(yWheel > 0 && yWheel < 64) { + clickedComponent = 0; + } + } + + int xValue = mouseX - (x+5+64+5); + int y = mouseY - this.y - 5; + + if(y > -5 && y <= 69) { + if(xValue > 0 && xValue < 10) { + clickedComponent = 1; + } + + int xOpacity = mouseX - (x+5+64+5+10+5); + + if(xOpacity > 0 && xOpacity < 10) { + clickedComponent = 2; + } + } + + int chromaSpeed = ChromaColour.getSpeed(colour); + int xChroma = mouseX - (x+5+64+5+10+5+10+5); + if(xChroma > 0 && xChroma < 10) { + if(chromaSpeed > 0) { + if(y > -5 && y <= 69) { + clickedComponent = 3; + } + } else if(mouseY > this.y+5+27 && mouseY < this.y+5+37) { + int currentColour = ChromaColour.specialToSimpleRGB(colour); + Color c = new Color(currentColour, true); + colour = ChromaColour.special(200, c.getAlpha(), currentColour); + colourChangedCallback.accept(colour); + } + } + } else { + hexField.unfocus(); + closeCallback.run(); + return false; + } + } + if(Mouse.isButtonDown(0) && clickedComponent >= 0) { + int currentColour = ChromaColour.specialToSimpleRGB(colour); + Color c = new Color(currentColour, true); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + + float xWheel = mouseXF - x - 5; + float yWheel = mouseYF - y - 5; + + if(clickedComponent == 0) { + float angle = (float) Math.toDegrees(Math.atan((32-xWheel)/(yWheel-32+1E-5))+Math.PI/2); + xWheel = Math.max(0, Math.min(64, xWheel)); + yWheel = Math.max(0, Math.min(64, yWheel)); + float radius = (float) Math.sqrt(((xWheel-32)*(xWheel-32)+(yWheel-32)*(yWheel-32))/1024f); + if(yWheel < 32) angle += 180; + + this.wheelAngle = angle; + this.wheelRadius = (float)Math.pow(Math.min(1, radius), 1.5f); + int rgb = Color.getHSBColor(angle/360f, wheelRadius, hsv[2]).getRGB(); + colour = ChromaColour.special(ChromaColour.getSpeed(colour), c.getAlpha(), rgb); + colourChangedCallback.accept(colour); + return true; + } + + float y = mouseYF - this.y - 5; + y = Math.max(0, Math.min(64, y)); + System.out.println(y); + + if(clickedComponent == 1) { + int rgb = Color.getHSBColor(wheelAngle/360, wheelRadius, 1-y/64f).getRGB(); + colour = ChromaColour.special(ChromaColour.getSpeed(colour), c.getAlpha(), rgb); + colourChangedCallback.accept(colour); + return true; + } + + if(clickedComponent == 2) { + colour = ChromaColour.special(ChromaColour.getSpeed(colour), + 255-Math.round(y/64f*255), currentColour); + colourChangedCallback.accept(colour); + return true; + } + + if(clickedComponent == 3) { + colour = ChromaColour.special(255-Math.round(y/64f*255), c.getAlpha(), currentColour); + colourChangedCallback.accept(colour); + } + return true; + } + return false; + } + + public boolean keyboardInput() { + if(Keyboard.getEventKeyState() && hexField.getFocus()) { + if (Keyboard.getEventKey() == Keyboard.KEY_ESCAPE) { + hexField.unfocus(); + return true; + } + String old = hexField.getText(); + + hexField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey()); + + if(hexField.getText().length() > 6) { + hexField.setText(old); + } else { + try { + String text = hexField.getText().toLowerCase(); + + int rgb = Integer.parseInt(text, 16); + int alpha = (ChromaColour.specialToSimpleRGB(colour) >> 24) & 0xFF; + colour = ChromaColour.special(ChromaColour.getSpeed(colour), alpha, rgb); + colourChangedCallback.accept(colour); + + Color c = new Color(rgb); + float[] hsv = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null); + updateAngleAndRadius(hsv); + } catch(Exception e) {}; + } + + return true; + } + return false; + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementTextField.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementTextField.java new file mode 100644 index 0000000..e2d6557 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiElementTextField.java @@ -0,0 +1,534 @@ +package com.thatgravyboat.skyblockhud.core; + +import com.thatgravyboat.skyblockhud.core.util.StringUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiTextField; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; + +import java.awt.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class GuiElementTextField { + + public static final int SCALE_TEXT = 0b100000; + public static final int NUM_ONLY = 0b10000; + public static final int NO_SPACE = 0b01000; + public static final int FORCE_CAPS = 0b00100; + public static final int COLOUR = 0b00010; + public static final int MULTILINE = 0b00001; + + private int searchBarYSize; + private int searchBarXSize; + private static final int searchBarPadding = 2; + + private int options; + + private boolean focus = false; + + private int x; + private int y; + + private String prependText = ""; + + private final GuiTextField textField = new GuiTextField(0, Minecraft.getMinecraft().fontRendererObj, + 0 , 0, 0, 0); + + private int customBorderColour = -1; + + public GuiElementTextField(String initialText, int options) { + this(initialText, 100, 20, options); + } + + public GuiElementTextField(String initialText, int sizeX, int sizeY, int options) { + textField.setFocused(true); + textField.setCanLoseFocus(false); + textField.setMaxStringLength(999); + textField.setText(initialText); + this.searchBarXSize = sizeX; + this.searchBarYSize = sizeY; + this.options = options; + } + + public void setMaxStringLength(int len) { + textField.setMaxStringLength(len); + } + + public void setCustomBorderColour(int colour) { + this.customBorderColour = colour; + } + + public String getText() { + return textField.getText(); + } + + public void setPrependText(String text) { + this.prependText = text; + } + + public void setText(String text) { + if(textField.getText() == null || !textField.getText().equals(text)) { + textField.setText(text); + } + } + + public void setSize(int searchBarXSize, int searchBarYSize) { + this.searchBarXSize = searchBarXSize; + this.searchBarYSize = searchBarYSize; + } + + public void setOptions(int options) { + this.options = options; + } + + @Override + public String toString() { + return textField.getText(); + } + + public void setFocus(boolean focus) { + this.focus = focus; + } + public boolean getFocus() { + return focus; + } + + public int getHeight() { + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + int paddingUnscaled = searchBarPadding/scaledresolution.getScaleFactor(); + + int numLines = org.apache.commons.lang3.StringUtils.countMatches(textField.getText(), "\n")+1; + int extraSize = (searchBarYSize-8)/2+8; + int bottomTextBox = searchBarYSize + extraSize*(numLines-1); + + return bottomTextBox + paddingUnscaled*2; + } + + public int getWidth() { + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + int paddingUnscaled = searchBarPadding/scaledresolution.getScaleFactor(); + + return searchBarXSize + paddingUnscaled*2; + } + + private float getScaleFactor(String str) { + return Math.min(1, (searchBarXSize-2)/(float)Minecraft.getMinecraft().fontRendererObj.getStringWidth(str)); + } + + private boolean isScaling() { + return (options & SCALE_TEXT) != 0; + } + + private float getStringWidth(String str) { + if(isScaling()) { + return Minecraft.getMinecraft().fontRendererObj.getStringWidth(str)*getScaleFactor(str); + } else { + return Minecraft.getMinecraft().fontRendererObj.getStringWidth(str); + } + } + + public int getCursorPos(int mouseX, int mouseY) { + int xComp = mouseX - x; + int yComp = mouseY - y; + + int extraSize = (searchBarYSize-8)/2+8; + + String renderText = prependText + textField.getText(); + + int lineNum = Math.round(((yComp - (searchBarYSize-8)/2))/extraSize); + + Pattern patternControlCode = Pattern.compile("(?i)\\u00A7([^\\u00B6])(?!\\u00B6)"); + String text = renderText; + String textNoColour = renderText; + if((options & COLOUR) != 0) { + while(true) { + Matcher matcher = patternControlCode.matcher(text); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + text = matcher.replaceFirst("\u00A7"+code+"\u00B6"+code); + } + } + while(true) { + Matcher matcher = patternControlCode.matcher(textNoColour); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + textNoColour = matcher.replaceFirst("\u00B6"+code); + } + + int currentLine = 0; + int cursorIndex = 0; + for(; cursorIndex<textNoColour.length(); cursorIndex++) { + if(currentLine == lineNum) break; + if(textNoColour.charAt(cursorIndex) == '\n') { + currentLine++; + } + } + + + String textNC = textNoColour.substring(0, cursorIndex); + int colorCodes = org.apache.commons.lang3.StringUtils.countMatches(textNC, "\u00B6"); + String line = text.substring(cursorIndex+(((options & COLOUR) != 0)?colorCodes*2:0)).split("\n")[0]; + int padding = Math.min(5, searchBarXSize-strLenNoColor(line))/2; + String trimmed = Minecraft.getMinecraft().fontRendererObj.trimStringToWidth(line, xComp-padding); + int linePos = strLenNoColor(trimmed); + if(linePos != strLenNoColor(line)) { + char after = line.charAt(linePos); + int trimmedWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(trimmed); + int charWidth = Minecraft.getMinecraft().fontRendererObj.getCharWidth(after); + if(trimmedWidth + charWidth/2 < xComp-padding) { + linePos++; + } + } + cursorIndex += linePos; + + int pre = StringUtils.cleanColour(prependText).length(); + if(cursorIndex < pre) { + cursorIndex = 0; + } else { + cursorIndex -= pre; + } + + return cursorIndex; + } + + public void mouseClicked(int mouseX, int mouseY, int mouseButton) { + if(mouseButton == 1) { + textField.setText(""); + } else { + textField.setCursorPosition(getCursorPos(mouseX, mouseY)); + } + focus = true; + } + + public void unfocus() { + focus = false; + textField.setSelectionPos(textField.getCursorPosition()); + } + + public int strLenNoColor(String str) { + return str.replaceAll("(?i)\\u00A7.", "").length(); + } + + public void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { + if(focus) { + textField.setSelectionPos(getCursorPos(mouseX, mouseY)); + } + } + + public void keyTyped(char typedChar, int keyCode) { + if(focus) { + if((options & MULTILINE) != 0) { //Carriage return + Pattern patternControlCode = Pattern.compile("(?i)\\u00A7([^\\u00B6\n])(?!\\u00B6)"); + + String text = textField.getText(); + String textNoColour = textField.getText(); + while(true) { + Matcher matcher = patternControlCode.matcher(text); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + text = matcher.replaceFirst("\u00A7"+code+"\u00B6"+code); + } + while(true) { + Matcher matcher = patternControlCode.matcher(textNoColour); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + textNoColour = matcher.replaceFirst("\u00B6"+code); + } + + if(keyCode == 28) { + String before = textField.getText().substring(0, textField.getCursorPosition()); + String after = textField.getText().substring(textField.getCursorPosition()); + int pos = textField.getCursorPosition(); + textField.setText(before + "\n" + after); + textField.setCursorPosition(pos+1); + return; + } else if(keyCode == 200) { //Up + String textNCBeforeCursor = textNoColour.substring(0, textField.getSelectionEnd()); + int colorCodes = org.apache.commons.lang3.StringUtils.countMatches(textNCBeforeCursor, "\u00B6"); + String textBeforeCursor = text.substring(0, textField.getSelectionEnd()+colorCodes*2); + + int numLinesBeforeCursor = org.apache.commons.lang3.StringUtils.countMatches(textBeforeCursor, "\n"); + + String[] split = textBeforeCursor.split("\n"); + int textBeforeCursorWidth; + String lineBefore; + String thisLineBeforeCursor; + if(split.length == numLinesBeforeCursor && split.length > 0) { + textBeforeCursorWidth = 0; + lineBefore = split[split.length-1]; + thisLineBeforeCursor = ""; + } else if(split.length > 1) { + thisLineBeforeCursor = split[split.length-1]; + lineBefore = split[split.length-2]; + textBeforeCursorWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(thisLineBeforeCursor); + } else { + return; + } + String trimmed = Minecraft.getMinecraft().fontRendererObj + .trimStringToWidth(lineBefore, textBeforeCursorWidth); + int linePos = strLenNoColor(trimmed); + if(linePos != strLenNoColor(lineBefore)) { + char after = lineBefore.charAt(linePos); + int trimmedWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(trimmed); + int charWidth = Minecraft.getMinecraft().fontRendererObj.getCharWidth(after); + if(trimmedWidth + charWidth/2 < textBeforeCursorWidth) { + linePos++; + } + } + int newPos = textField.getSelectionEnd()-strLenNoColor(thisLineBeforeCursor) + -strLenNoColor(lineBefore)-1+linePos; + + if(GuiScreen.isShiftKeyDown()) { + textField.setSelectionPos(newPos); + } else { + textField.setCursorPosition(newPos); + } + } else if(keyCode == 208) { //Down + String textNCBeforeCursor = textNoColour.substring(0, textField.getSelectionEnd()); + int colorCodes = org.apache.commons.lang3.StringUtils.countMatches(textNCBeforeCursor, "\u00B6"); + String textBeforeCursor = text.substring(0, textField.getSelectionEnd()+colorCodes*2); + + int numLinesBeforeCursor = org.apache.commons.lang3.StringUtils.countMatches(textBeforeCursor, "\n"); + + String[] split = textBeforeCursor.split("\n"); + String thisLineBeforeCursor; + int textBeforeCursorWidth; + if(split.length == numLinesBeforeCursor) { + thisLineBeforeCursor = ""; + textBeforeCursorWidth = 0; + } else if(split.length > 0) { + thisLineBeforeCursor = split[split.length-1]; + textBeforeCursorWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(thisLineBeforeCursor); + } else { + return; + } + + String[] split2 = textNoColour.split("\n"); + if(split2.length > numLinesBeforeCursor+1) { + String lineAfter = split2[numLinesBeforeCursor+1]; + String trimmed = Minecraft.getMinecraft().fontRendererObj + .trimStringToWidth(lineAfter, textBeforeCursorWidth); + int linePos = strLenNoColor(trimmed); + if(linePos != strLenNoColor(lineAfter)) { + char after = lineAfter.charAt(linePos); + int trimmedWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(trimmed); + int charWidth = Minecraft.getMinecraft().fontRendererObj.getCharWidth(after); + if(trimmedWidth + charWidth/2 < textBeforeCursorWidth) { + linePos++; + } + } + int newPos = textField.getSelectionEnd()-strLenNoColor(thisLineBeforeCursor) + +strLenNoColor(split2[numLinesBeforeCursor])+1+linePos; + + if(GuiScreen.isShiftKeyDown()) { + textField.setSelectionPos(newPos); + } else { + textField.setCursorPosition(newPos); + } + } + } + } + + String old = textField.getText(); + if((options & FORCE_CAPS) != 0) typedChar = Character.toUpperCase(typedChar); + if((options & NO_SPACE) != 0 && typedChar == ' ') return; + + textField.setFocused(true); + textField.textboxKeyTyped(typedChar, keyCode); + + if((options & COLOUR) != 0) { + if(typedChar == '&') { + int pos = textField.getCursorPosition()-2; + if(pos >= 0 && pos < textField.getText().length()) { + if(textField.getText().charAt(pos) == '&') { + String before = textField.getText().substring(0, pos); + String after = ""; + if(pos+2 < textField.getText().length()) { + after = textField.getText().substring(pos+2); + } + textField.setText(before + "\u00A7" + after); + textField.setCursorPosition(pos+1); + } + } + } + } + + if((options & NUM_ONLY) != 0 && textField.getText().matches("[^0-9.]")) textField.setText(old); + } + } + + public void render(int x, int y) { + this.x = x; + this.y = y; + drawTextbox(x, y, searchBarXSize, searchBarYSize, searchBarPadding, textField, focus); + } + + private void drawTextbox(int x, int y, int searchBarXSize, int searchBarYSize, int searchBarPadding, + GuiTextField textField, boolean focus) { + ScaledResolution scaledresolution = new ScaledResolution(Minecraft.getMinecraft()); + String renderText = prependText + textField.getText(); + + GlStateManager.disableLighting(); + + /** + * Search bar + */ + int paddingUnscaled = searchBarPadding/scaledresolution.getScaleFactor(); + if(paddingUnscaled < 1) paddingUnscaled = 1; + + int numLines = org.apache.commons.lang3.StringUtils.countMatches(renderText, "\n")+1; + int extraSize = (searchBarYSize-8)/2+8; + int bottomTextBox = y + searchBarYSize + extraSize*(numLines-1); + + int borderColour = focus ? Color.GREEN.getRGB() : Color.WHITE.getRGB(); + if(customBorderColour != -1) { + borderColour = customBorderColour; + } + //bar background + Gui.drawRect(x - paddingUnscaled, + y - paddingUnscaled, + x + searchBarXSize + paddingUnscaled, + bottomTextBox + paddingUnscaled, borderColour); + Gui.drawRect(x, + y, + x + searchBarXSize, + bottomTextBox, Color.BLACK.getRGB()); + + //bar text + Pattern patternControlCode = Pattern.compile("(?i)\\u00A7([^\\u00B6\n])(?!\\u00B6)"); + + String text = renderText; + String textNoColor = renderText; + if((options & COLOUR) != 0) { + while(true) { + Matcher matcher = patternControlCode.matcher(text); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + text = matcher.replaceFirst("\u00A7"+code+"\u00B6"+code); + } + } + while(true) { + Matcher matcher = patternControlCode.matcher(textNoColor); + if(!matcher.find() || matcher.groupCount() < 1) break; + String code = matcher.group(1); + textNoColor = matcher.replaceFirst("\u00B6"+code); + } + + int xStartOffset = 5; + float scale = 1; + String[] texts = text.split("\n"); + for(int yOffI = 0; yOffI < texts.length; yOffI++) { + int yOff = yOffI*extraSize; + + if(isScaling() && Minecraft.getMinecraft().fontRendererObj.getStringWidth(texts[yOffI])>searchBarXSize-10) { + scale = (searchBarXSize-2)/(float)Minecraft.getMinecraft().fontRendererObj.getStringWidth(texts[yOffI]); + if(scale > 1) scale=1; + float newLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(texts[yOffI])*scale; + xStartOffset = (int)((searchBarXSize-newLen)/2f); + + TextRenderUtils.drawStringCenteredScaledMaxWidth(texts[yOffI], Minecraft.getMinecraft().fontRendererObj, x+searchBarXSize/2f, + y+searchBarYSize/2f+yOff, false, + searchBarXSize-2, Color.WHITE.getRGB()); + } else { + Minecraft.getMinecraft().fontRendererObj.drawString(StringUtils.trimToWidth(texts[yOffI], searchBarXSize-10), x + 5, + y+(searchBarYSize-8)/2+yOff, Color.WHITE.getRGB()); + } + } + + if(focus && System.currentTimeMillis()%1000>500) { + String textNCBeforeCursor = textNoColor.substring(0, textField.getCursorPosition()+prependText.length()); + int colorCodes = org.apache.commons.lang3.StringUtils.countMatches(textNCBeforeCursor, "\u00B6"); + String textBeforeCursor = text.substring(0, textField.getCursorPosition()+prependText.length()+(((options & COLOUR) != 0) ? colorCodes*2 : 0)); + + int numLinesBeforeCursor = org.apache.commons.lang3.StringUtils.countMatches(textBeforeCursor, "\n"); + int yOff = numLinesBeforeCursor*extraSize; + + String[] split = textBeforeCursor.split("\n"); + int textBeforeCursorWidth; + if(split.length <= numLinesBeforeCursor || split.length == 0) { + textBeforeCursorWidth = 0; + } else { + textBeforeCursorWidth = (int)(Minecraft.getMinecraft().fontRendererObj.getStringWidth(split[split.length-1])*scale); + } + Gui.drawRect(x + xStartOffset + textBeforeCursorWidth, + y+(searchBarYSize-8)/2-1 + yOff, + x + xStartOffset + textBeforeCursorWidth+1, + y+(searchBarYSize-8)/2+9 + yOff, Color.WHITE.getRGB()); + } + + String selectedText = textField.getSelectedText(); + if(!selectedText.isEmpty()) { + System.out.println("Start"); + int leftIndex = Math.min(textField.getCursorPosition()+prependText.length(), textField.getSelectionEnd()+prependText.length()); + int rightIndex = Math.max(textField.getCursorPosition()+prependText.length(), textField.getSelectionEnd()+prependText.length()); + + float texX = 0; + int texY = 0; + boolean sectionSignPrev = false; + boolean ignoreNext = false; + boolean bold = false; + for(int i=0; i<textNoColor.length(); i++) { + if(ignoreNext) { + ignoreNext = false; + continue; + } + + char c = textNoColor.charAt(i); + if(sectionSignPrev) { + if(c != 'k' && c != 'K' + && c != 'm' && c != 'M' + && c != 'n' && c != 'N' + && c != 'o' && c != 'O') { + bold = c == 'l' || c == 'L'; + } + sectionSignPrev = false; + if(i < prependText.length()) continue; + } + if(c == '\u00B6') { + sectionSignPrev = true; + if(i < prependText.length()) continue; + } + + if(c == '\n') { + if(i >= leftIndex && i < rightIndex) { + Gui.drawRect(x + xStartOffset + (int)texX, + y+(searchBarYSize-8)/2-1 + texY, + x + xStartOffset + (int)texX + 3, + y+(searchBarYSize-8)/2+9 + texY, Color.LIGHT_GRAY.getRGB()); + } + + texX = 0; + texY += extraSize; + continue; + } + + //String c2 = bold ? EnumChatFormatting.BOLD.toString() : "" + c; + + System.out.println("Adding len for char:"+c+":"+Integer.toHexString(c)); + int len = Minecraft.getMinecraft().fontRendererObj.getStringWidth(String.valueOf(c)); + if(bold) len++; + if(i >= leftIndex && i < rightIndex) { + Gui.drawRect(x + xStartOffset + (int)texX, + y+(searchBarYSize-8)/2-1 + texY, + x + xStartOffset + (int)(texX + len*scale), + y+(searchBarYSize-8)/2+9 + texY, Color.LIGHT_GRAY.getRGB()); + + TextRenderUtils.drawStringScaled(String.valueOf(c), Minecraft.getMinecraft().fontRendererObj, + x + xStartOffset + texX, + y+searchBarYSize/2f-scale*8/2f + texY, false, Color.BLACK.getRGB(), scale); + if(bold) { + TextRenderUtils.drawStringScaled(String.valueOf(c), Minecraft.getMinecraft().fontRendererObj, + x + xStartOffset + texX + 1, + y+searchBarYSize/2f-scale*8/2f + texY, false, Color.BLACK.getRGB(), scale); + } + } + + texX += len*scale; + } + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/GuiScreenElementWrapper.java b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiScreenElementWrapper.java new file mode 100644 index 0000000..234cc2d --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/GuiScreenElementWrapper.java @@ -0,0 +1,35 @@ +package com.thatgravyboat.skyblockhud.core; + +import net.minecraft.client.gui.GuiScreen; +import org.lwjgl.input.Mouse; + +import java.io.IOException; + +public class GuiScreenElementWrapper extends GuiScreen { + + public final GuiElement element; + + public GuiScreenElementWrapper(GuiElement element) { + this.element = element; + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + super.drawScreen(mouseX, mouseY, partialTicks); + element.render(); + } + + @Override + public void handleMouseInput() throws IOException { + super.handleMouseInput(); + int i = Mouse.getEventX() * this.width / this.mc.displayWidth; + int j = this.height - Mouse.getEventY() * this.height / this.mc.displayHeight - 1; + element.mouseInput(i, j); + } + + @Override + public void handleKeyboardInput() throws IOException { + super.handleKeyboardInput(); + element.keyboardInput(); + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/Config.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/Config.java new file mode 100644 index 0000000..40f8c0e --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/Config.java @@ -0,0 +1,8 @@ +package com.thatgravyboat.skyblockhud.core.config; + +public class Config { + + public void executeRunnable(String runnableId) { + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/Position.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/Position.java new file mode 100644 index 0000000..1c2de86 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/Position.java @@ -0,0 +1,196 @@ +package com.thatgravyboat.skyblockhud.core.config; + +import com.google.gson.annotations.Expose; +import net.minecraft.client.gui.ScaledResolution; + +public class Position { + + @Expose + private int x; + @Expose + private int y; + @Expose + private boolean centerX; + @Expose + private boolean centerY; + + + private static final int EDGE_OFFSET = 0; + + public Position(int x, int y) { + this(x, y, false, false); + } + + public Position(int x, int y, boolean centerX, boolean centerY) { + this.x = x; + this.y = y; + this.centerX = centerX; + this.centerY = centerY; + } + + public void set(Position other) { + this.x = other.x; + this.y = other.y; + this.centerX = other.centerX; + this.centerY = other.centerY; + } + + public Position clone() { + return new Position(x, y, centerX, centerY); + } + + public boolean isCenterX() { + return centerX; + } + + public boolean isCenterY() { + return centerY; + } + + public int getRawX() { + return x; + } + + public int getRawY() { + return y; + } + + public int getAbsX(ScaledResolution scaledResolution, int objWidth) { + int width = scaledResolution.getScaledWidth(); + + if(centerX) { + return width/2 + x; + } + + int ret = x; + if(x < 0) { + ret = width + x - objWidth; + } + + if(ret < 0) ret = 0; + if(ret > width - objWidth) ret = width - objWidth; + + return ret; + } + + public int getAbsY(ScaledResolution scaledResolution, int objHeight) { + int height = scaledResolution.getScaledHeight(); + + if(centerY) { + return height/2 + y; + } + + int ret = y; + if(y < 0) { + ret = height + y - objHeight; + } + + if(ret < 0) ret = 0; + if(ret > height - objHeight) ret = height - objHeight; + + return ret; + } + + public int moveX(int deltaX, int objWidth, ScaledResolution scaledResolution) { + int screenWidth = scaledResolution.getScaledWidth(); + boolean wasPositiveX = this.x >= 0; + this.x += deltaX; + + if(centerX) { + if(wasPositiveX) { + if(this.x > screenWidth/2-objWidth/2) { + deltaX += screenWidth/2-objWidth/2-this.x; + this.x = screenWidth/2-objWidth/2; + } + } else { + if(this.x < -screenWidth/2+objWidth/2) { + deltaX += -screenWidth/2+objWidth/2-this.x; + this.x = -screenWidth/2+objWidth/2; + } + } + return deltaX; + } + + if(wasPositiveX) { + if(this.x < EDGE_OFFSET) { + deltaX += EDGE_OFFSET-this.x; + this.x = EDGE_OFFSET; + } + if(this.x > screenWidth-EDGE_OFFSET) { + deltaX += screenWidth-EDGE_OFFSET-this.x; + this.x = screenWidth-EDGE_OFFSET; + } + } else { + if(this.x+1 > -EDGE_OFFSET) { + deltaX += -EDGE_OFFSET-1-this.x; + this.x = -EDGE_OFFSET-1; + } + if(this.x+screenWidth < EDGE_OFFSET) { + deltaX += EDGE_OFFSET-screenWidth-this.x; + this.x = EDGE_OFFSET-screenWidth; + } + } + + if(this.x >= 0 && this.x+objWidth/2 > screenWidth/2) { + this.x -= screenWidth - objWidth; + } + if(this.x < 0 && this.x+objWidth/2 <= -screenWidth/2) { + this.x += screenWidth - objWidth; + } + return deltaX; + } + + public int moveY(int deltaY, int objHeight, ScaledResolution scaledResolution) { + int screenHeight = scaledResolution.getScaledHeight(); + boolean wasPositiveY = this.y >= 0; + this.y += deltaY; + + if(centerY) { + if(wasPositiveY) { + if(this.y > screenHeight/2-objHeight/2) { + deltaY += screenHeight/2-objHeight/2-this.y; + this.y = screenHeight/2-objHeight/2; + } + } else { + if(this.y < -screenHeight/2+objHeight/2) { + deltaY += -screenHeight/2+objHeight/2-this.y; + this.y = -screenHeight/2+objHeight/2; + } + } + return deltaY; + } + + if(wasPositiveY) { + if(this.y < EDGE_OFFSET) { + deltaY += EDGE_OFFSET-this.y; + this.y = EDGE_OFFSET; + } + if(this.y > screenHeight-EDGE_OFFSET) { + deltaY += screenHeight-EDGE_OFFSET-this.y; + this.y = screenHeight-EDGE_OFFSET; + } + } else { + if(this.y+1 > -EDGE_OFFSET) { + deltaY += -EDGE_OFFSET-1-this.y; + this.y = -EDGE_OFFSET-1; + } + if(this.y+screenHeight < EDGE_OFFSET) { + deltaY += EDGE_OFFSET-screenHeight-this.y; + this.y = EDGE_OFFSET-screenHeight; + } + } + + if(this.y >= 0 && this.y-objHeight/2 > screenHeight/2) { + this.y -= screenHeight - objHeight; + } + if(this.y < 0 && this.y-objHeight/2 <= -screenHeight/2) { + this.y += screenHeight - objHeight; + } + return deltaY; + } + + public boolean rightAligned(ScaledResolution scaledResolution, int objWidth){ + return this.getAbsX(scaledResolution, objWidth) > (scaledResolution.getScaledWidth() / 2); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/Category.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/Category.java new file mode 100644 index 0000000..e1d51ac --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/Category.java @@ -0,0 +1,15 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Category { + + String name(); + String desc(); + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigAccordionId.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigAccordionId.java new file mode 100644 index 0000000..8e2836f --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigAccordionId.java @@ -0,0 +1,14 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigAccordionId { + + int id(); + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorAccordion.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorAccordion.java new file mode 100644 index 0000000..acb60af --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorAccordion.java @@ -0,0 +1,14 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorAccordion { + + int id(); + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorBoolean.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorBoolean.java new file mode 100644 index 0000000..b1846d3 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorBoolean.java @@ -0,0 +1,12 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorBoolean { + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorButton.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorButton.java new file mode 100644 index 0000000..32425d1 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorButton.java @@ -0,0 +1,15 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorButton { + + String runnableId(); + String buttonText() default ""; + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorColour.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorColour.java new file mode 100644 index 0000000..1e5713c --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorColour.java @@ -0,0 +1,13 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorColour { + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDraggableList.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDraggableList.java new file mode 100644 index 0000000..963c305 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDraggableList.java @@ -0,0 +1,14 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorDraggableList { + + String[] exampleText(); + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDropdown.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDropdown.java new file mode 100644 index 0000000..5e48e25 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorDropdown.java @@ -0,0 +1,16 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorDropdown { + + String[] values(); + int initialIndex() default 0; + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorSlider.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorSlider.java new file mode 100644 index 0000000..a0fea03 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorSlider.java @@ -0,0 +1,18 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorSlider { + + float minValue(); + float maxValue(); + + float minStep(); + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorText.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorText.java new file mode 100644 index 0000000..0c00561 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigEditorText.java @@ -0,0 +1,13 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigEditorText { + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigOption.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigOption.java new file mode 100644 index 0000000..845d01f --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/annotations/ConfigOption.java @@ -0,0 +1,17 @@ +package com.thatgravyboat.skyblockhud.core.config.annotations; + + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface ConfigOption { + + String name(); + String desc(); + int subcategoryId() default -1; + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditor.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditor.java new file mode 100644 index 0000000..e978420 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditor.java @@ -0,0 +1,62 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; + +public abstract class GuiOptionEditor { + + protected final ConfigProcessor.ProcessedOption option; + private static final int HEIGHT = 45; + + public GuiOptionEditor(ConfigProcessor.ProcessedOption option) { + this.option = option; + } + + public void render(int x, int y, int width) { + int height = getHeight(); + + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + RenderUtils.drawFloatingRectDark(x, y, width, height, true); + TextRenderUtils.drawStringCenteredScaledMaxWidth(option.name, + fr, x+width/6f, y+13, true, width/3-10, 0xc0c0c0); + + int maxLines = 5; + float scale = 1; + int lineCount = fr.listFormattedStringToWidth(option.desc, width*2/3-10).size(); + + if(lineCount <= 0) return; + + float paraHeight = 9 * lineCount - 1; + + while(paraHeight >= HEIGHT-10) { + scale -= 1/8f; + lineCount = fr.listFormattedStringToWidth(option.desc, (int)(width*2/3/scale-10)).size(); + paraHeight = (int)(9*scale * lineCount - 1*scale); + } + + GlStateManager.pushMatrix(); + GlStateManager.translate(x+5+width/3f, y+HEIGHT/2f-paraHeight/2, 0); + GlStateManager.scale(scale, scale, 1); + + fr.drawSplitString(option.desc, 0, 0, (int)(width*2/3/scale-10), 0xc0c0c0); + + GlStateManager.popMatrix(); + } + + public int getHeight() { + return HEIGHT; + } + + public abstract boolean mouseInput(int x, int y, int width, int mouseX, int mouseY); + public abstract boolean keyboardInput(); + + public boolean mouseInputOverlay(int x, int y, int width, int mouseX, int mouseY) { + return false; + } + public void renderOverlay(int x, int y, int width) {} + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorAccordion.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorAccordion.java new file mode 100644 index 0000000..c2b129d --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorAccordion.java @@ -0,0 +1,82 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +public class GuiOptionEditorAccordion extends GuiOptionEditor { + + private int accordionId; + private boolean accordionToggled; + + public GuiOptionEditorAccordion(ConfigProcessor.ProcessedOption option, int accordionId) { + super(option); + this.accordionToggled = (boolean) option.get(); + this.accordionId = accordionId; + } + + @Override + public int getHeight() { + return 20; + } + + public int getAccordionId() { + return accordionId; + } + + public boolean getToggled() { + return accordionToggled; + } + + @Override + public void render(int x, int y, int width) { + int height = getHeight(); + RenderUtils.drawFloatingRectDark(x, y, width, height, true); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + GlStateManager.enableBlend(); + GlStateManager.disableTexture2D(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.color(1, 1, 1, 1); + worldrenderer.begin(GL11.GL_TRIANGLES, DefaultVertexFormats.POSITION); + if(accordionToggled) { + worldrenderer.pos((double)x+6, (double)y+6, 0.0D).endVertex(); + worldrenderer.pos((double)x+9.75f, (double)y+13.5f, 0.0D).endVertex(); + worldrenderer.pos((double)x+13.5f, (double)y+6, 0.0D).endVertex(); + } else { + worldrenderer.pos((double)x+6, (double)y+13.5f, 0.0D).endVertex(); + worldrenderer.pos((double)x+13.5f, (double)y+9.75f, 0.0D).endVertex(); + worldrenderer.pos((double)x+6, (double)y+6, 0.0D).endVertex(); + } + tessellator.draw(); + GlStateManager.enableTexture2D(); + GlStateManager.disableBlend(); + + TextRenderUtils.drawStringScaledMaxWidth(option.name, Minecraft.getMinecraft().fontRendererObj, + x+18, y+6, false, width-10, 0xc0c0c0); + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + if(Mouse.getEventButtonState() && mouseX > x && mouseX < x+ width && + mouseY > y && mouseY < y+getHeight()) { + accordionToggled = !accordionToggled; + return true; + } + + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorBoolean.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorBoolean.java new file mode 100644 index 0000000..3ea70c0 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorBoolean.java @@ -0,0 +1,38 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.GuiElementBoolean; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; + +public class GuiOptionEditorBoolean extends GuiOptionEditor { + + private final GuiElementBoolean bool; + + public GuiOptionEditorBoolean(ConfigProcessor.ProcessedOption option) { + super(option); + + bool = new GuiElementBoolean(0, 0, (boolean)option.get(), 10, option::set); + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + int height = getHeight(); + + bool.x = x+width/6-24; + bool.y = y+height-7-14; + bool.render(); + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + bool.x = x+width/6-24; + bool.y = y+height-7-14; + return bool.mouseInput(mouseX, mouseY); + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorButton.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorButton.java new file mode 100644 index 0000000..752b4bf --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorButton.java @@ -0,0 +1,64 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.ChromaColour; +import com.thatgravyboat.skyblockhud.core.config.Config; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import org.lwjgl.input.Mouse; + +import static com.thatgravyboat.skyblockhud.GuiTextures.button_tex; + +public class GuiOptionEditorButton extends GuiOptionEditor { + + private final String runnableId; + private String buttonText; + private Config config; + + public GuiOptionEditorButton(ConfigProcessor.ProcessedOption option, String runnableId, String buttonText, Config config) { + super(option); + this.runnableId = runnableId; + this.config = config; + + this.buttonText = buttonText; + if(this.buttonText != null && this.buttonText.isEmpty()) this.buttonText = null; + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + + int height = getHeight(); + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(button_tex); + RenderUtils.drawTexturedRect(x+width/6-24, y+height-7-14, 48, 16); + + if(buttonText != null) { + TextRenderUtils.drawStringCenteredScaledMaxWidth(buttonText, Minecraft.getMinecraft().fontRendererObj, + x+width/6, y+height-7-6, + false, 44, 0xFF303030); + } + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + if(Mouse.getEventButtonState()) { + int height = getHeight(); + if(mouseX > x+width/6-24 && mouseX < x+width/6+24 && + mouseY > y+height-7-14 && mouseY < y+height-7+2) { + config.executeRunnable(runnableId); + return true; + } + } + + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorColour.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorColour.java new file mode 100644 index 0000000..1f03954 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorColour.java @@ -0,0 +1,71 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.ChromaColour; +import com.thatgravyboat.skyblockhud.core.GuiElementColour; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.GlStateManager; +import org.lwjgl.input.Mouse; + +import static com.thatgravyboat.skyblockhud.GuiTextures.*; + +public class GuiOptionEditorColour extends GuiOptionEditor { + + private String chromaColour; + private GuiElementColour colourElement = null; + + public GuiOptionEditorColour(ConfigProcessor.ProcessedOption option) { + super(option); + + this.chromaColour = (String)option.get(); + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + int height = getHeight(); + + int argb = ChromaColour.specialToChromaRGB(chromaColour); + int r = (argb >> 16) & 0xFF; + int g = (argb >> 8) & 0xFF; + int b = argb & 0xFF; + GlStateManager.color(r/255f, g/255f, b/255f, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(button_white); + RenderUtils.drawTexturedRect(x+width/6f-24, y+height-7-14, 48, 16); + } + + @Override + public void renderOverlay(int x, int y, int width) { + if(colourElement != null) { + colourElement.render(); + } + } + + @Override + public boolean mouseInputOverlay(int x, int y, int width, int mouseX, int mouseY) { + return colourElement != null && colourElement.mouseInput(mouseX, mouseY); + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + + if(Mouse.getEventButtonState() && Mouse.getEventButton() == 0 && + mouseX > x+width/6-24 && mouseX < x+width/6+24 && + mouseY > y+height-7-14 && mouseY < y+height-7+2) { + colourElement = new GuiElementColour(mouseX, mouseY, (String) option.get(), (val) -> { + option.set(val); + chromaColour = val; + }, () -> colourElement = null); + } + + return false; + } + + @Override + public boolean keyboardInput() { + return colourElement != null && colourElement.keyboardInput(); + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDraggableList.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDraggableList.java new file mode 100644 index 0000000..59f9e82 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDraggableList.java @@ -0,0 +1,284 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.lerp.LerpUtils; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.util.EnumChatFormatting; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; + +import static com.thatgravyboat.skyblockhud.GuiTextures.button_tex; + +public class GuiOptionEditorDraggableList extends GuiOptionEditor { + + private static final ResourceLocation DELETE = new ResourceLocation("notenoughupdates:core/delete.png"); + + private String[] exampleText; + private List<Integer> activeText; + private int currentDragging = -1; + private int dragStartIndex = -1; + + private long trashHoverTime = -1; + + private int dragOffsetX = -1; + private int dragOffsetY = -1; + + private boolean dropdownOpen = false; + + public GuiOptionEditorDraggableList(ConfigProcessor.ProcessedOption option, String[] exampleText) { + super(option); + + this.exampleText = exampleText; + this.activeText = (List<Integer>) option.get(); + } + + @Override + public int getHeight() { + int height = super.getHeight() + 13; + + for(int strIndex : activeText) { + String str = exampleText[strIndex]; + height += 10 * str.split("\n").length; + } + + return height; + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + + int height = getHeight(); + + GlStateManager.color(1, 1, 1, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(button_tex); + RenderUtils.drawTexturedRect(x+width/6f-24, y+45-7-14, 48, 16); + + TextRenderUtils.drawStringCenteredScaledMaxWidth("Add", Minecraft.getMinecraft().fontRendererObj, + x+width/6f, y+45-7-6, + false, 44, 0xFF303030); + + long currentTime = System.currentTimeMillis(); + float greenBlue = LerpUtils.clampZeroOne(((trashHoverTime < 0 ? 250 : 0) + trashHoverTime - currentTime)/250f); + GlStateManager.color(1, greenBlue, greenBlue, 1); + Minecraft.getMinecraft().getTextureManager().bindTexture(DELETE); + Utils.drawTexturedRect(x+width/6f+27, y+45-7-13, 11, 14, GL11.GL_NEAREST); + + Gui.drawRect(x+5, y+45, x+width-5, y+height-5, 0xffdddddd); + Gui.drawRect(x+6, y+46, x+width-6, y+height-6, 0xff000000); + + int i = 0; + int yOff=0; + for(int strIndex : activeText) { + String str = exampleText[strIndex]; + + String[] multilines = str.split("\n"); + + int ySize = multilines.length * 10; + + if(i++ != dragStartIndex) { + for(int multilineIndex=0; multilineIndex<multilines.length; multilineIndex++) { + String line = multilines[multilineIndex]; + Utils.drawStringScaledMaxWidth(line+EnumChatFormatting.RESET, Minecraft.getMinecraft().fontRendererObj, + x+20, y+50+yOff+multilineIndex*10, true, width-20, 0xffffffff); + } + Minecraft.getMinecraft().fontRendererObj.drawString("\u2261", x+10, y+50+yOff + ySize/2f - 4, 0xffffff, true); + } + + yOff += ySize; + } + } + + @Override + public void renderOverlay(int x, int y, int width) { + super.renderOverlay(x, y, width); + + if(dropdownOpen) { + List<Integer> remaining = new ArrayList<>(); + for(int i=0; i<exampleText.length; i++) { + remaining.add(i); + } + remaining.removeAll(activeText); + + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + int dropdownWidth = Math.min(width/2-10, 150); + int left = dragOffsetX; + int top = dragOffsetY; + + int dropdownHeight = -1 + 12*remaining.size(); + + int main = 0xff202026; + int outline = 0xff404046; + Gui.drawRect(left, top, left+1, top+dropdownHeight, outline); //Left + Gui.drawRect(left+1, top, left+dropdownWidth, top+1, outline); //Top + Gui.drawRect(left+dropdownWidth-1, top+1, left+dropdownWidth, top+dropdownHeight, outline); //Right + Gui.drawRect(left+1, top+dropdownHeight-1, left+dropdownWidth-1, top+dropdownHeight, outline); //Bottom + Gui.drawRect(left+1, top+1, left+dropdownWidth-1, top+dropdownHeight-1, main); //Middle + + int dropdownY = -1; + for(int strIndex : remaining) { + String str = exampleText[strIndex]; + if(str.isEmpty()) { + str = "<NONE>"; + } + TextRenderUtils.drawStringScaledMaxWidth(str.replaceAll("(\n.*)+", " ..."), + fr, left+3, top+3+dropdownY, false, dropdownWidth-6, 0xffa0a0a0); + dropdownY += 12; + } + } else if(currentDragging >= 0) { + int opacity = 0x80; + long currentTime = System.currentTimeMillis(); + if(trashHoverTime < 0) { + float greenBlue = LerpUtils.clampZeroOne((currentTime + trashHoverTime)/250f); + opacity = (int)(opacity * greenBlue); + } else { + float greenBlue = LerpUtils.clampZeroOne((250 + trashHoverTime - currentTime)/250f); + opacity = (int)(opacity * greenBlue); + } + + if(opacity < 20) return; + + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int mouseX = Mouse.getX() * scaledResolution.getScaledWidth() / Minecraft.getMinecraft().displayWidth; + int mouseY = scaledResolution.getScaledHeight() - Mouse.getY() * scaledResolution.getScaledHeight() / Minecraft.getMinecraft().displayHeight - 1; + + String str = exampleText[currentDragging]; + + String[] multilines = str.split("\n"); + + GlStateManager.enableBlend(); + for(int multilineIndex=0; multilineIndex<multilines.length; multilineIndex++) { + String line = multilines[multilineIndex]; + Utils.drawStringScaledMaxWidth(line+EnumChatFormatting.RESET, Minecraft.getMinecraft().fontRendererObj, + dragOffsetX + mouseX + 10, dragOffsetY + mouseY + multilineIndex*10, true, width-20, 0xffffff | (opacity << 24)); + } + + int ySize = multilines.length * 10; + + Minecraft.getMinecraft().fontRendererObj.drawString("\u2261", + dragOffsetX + mouseX, + dragOffsetY + mouseY + ySize/2f - 4, 0xffffff, true); + } + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + if(!Mouse.getEventButtonState() && !dropdownOpen && + dragStartIndex >= 0 && Mouse.getEventButton() == 0 && + mouseX >= x+width/6+27-3 && mouseX <= x+width/6+27+11+3 && + mouseY >= y+45-7-13-3 && mouseY <= y+45-7-13+14+3) { + activeText.remove(dragStartIndex); + currentDragging = -1; + dragStartIndex = -1; + return false; + } + + if(!Mouse.isButtonDown(0) || dropdownOpen) { + currentDragging = -1; + dragStartIndex = -1; + if(trashHoverTime > 0) trashHoverTime = -System.currentTimeMillis(); + } else if(currentDragging >= 0 && + mouseX >= x+width/6+27-3 && mouseX <= x+width/6+27+11+3 && + mouseY >= y+45-7-13-3 && mouseY <= y+45-7-13+14+3) { + if(trashHoverTime < 0) trashHoverTime = System.currentTimeMillis(); + } else { + if(trashHoverTime > 0) trashHoverTime = -System.currentTimeMillis(); + } + + if(Mouse.getEventButtonState()) { + int height = getHeight(); + + if(dropdownOpen) { + List<Integer> remaining = new ArrayList<>(); + for(int i=0; i<exampleText.length; i++) { + remaining.add(i); + } + remaining.removeAll(activeText); + + int dropdownWidth = Math.min(width/2-10, 150); + int left = dragOffsetX; + int top = dragOffsetY; + + int dropdownHeight = -1 + 12*remaining.size(); + + if(mouseX > left && mouseX < left+dropdownWidth && + mouseY > top && mouseY < top + dropdownHeight) { + int dropdownY = -1; + for(int strIndex : remaining) { + if(mouseY < top+dropdownY+12) { + activeText.add(0, strIndex); + if(remaining.size() == 1) dropdownOpen = false; + return true; + } + + dropdownY += 12; + } + } + + dropdownOpen = false; + return true; + } + + if(activeText.size() < exampleText.length && + mouseX > x+width/6-24 && mouseX < x+width/6+24 && + mouseY > y+45-7-14 && mouseY < y+45-7+2) { + dropdownOpen = !dropdownOpen; + dragOffsetX = mouseX; + dragOffsetY = mouseY; + return true; + } + + if(Mouse.getEventButton() == 0 && + mouseX > x+5 && mouseX < x+width-5 && + mouseY > y+45 && mouseY < y+height-6) { + int yOff=0; + int i = 0; + for(int strIndex : activeText) { + int ySize = 10 * exampleText[strIndex].split("\n").length; + if(mouseY < y+50+yOff+ySize) { + dragOffsetX = x+10 - mouseX; + dragOffsetY = y+50+yOff - mouseY; + + currentDragging = strIndex; + dragStartIndex = i; + break; + } + yOff += ySize; + i++; + } + } + } else if(Mouse.getEventButton() == -1 && currentDragging >= 0) { + int yOff=0; + int i = 0; + for(int strIndex : activeText) { + if(dragOffsetY + mouseY + 4 < y+50+yOff+10) { + activeText.remove(dragStartIndex); + activeText.add(i, currentDragging); + + dragStartIndex = i; + break; + } + yOff += 10 * exampleText[strIndex].split("\n").length; + i++; + } + } + + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDropdown.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDropdown.java new file mode 100644 index 0000000..5c797ad --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorDropdown.java @@ -0,0 +1,152 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.render.RenderUtils; +import com.thatgravyboat.skyblockhud.core.util.render.TextRenderUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.renderer.GlStateManager; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +public class GuiOptionEditorDropdown extends GuiOptionEditor { + + private final String[] values; + private final boolean useOrdinal; + private int selected; + private boolean open = false; + + public GuiOptionEditorDropdown(ConfigProcessor.ProcessedOption option, String[] values, int selected, boolean useOrdinal) { + super(option); + if(selected >= values.length) selected = values.length; + this.values = values; + this.selected = selected; + this.useOrdinal = useOrdinal; + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + + if(!open) { + int height = getHeight(); + + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + int dropdownWidth = Math.min(width/3-10, 80); + int left = x+width/6-dropdownWidth/2; + int top = y+height-7-14; + + String selectedString = " - Select - "; + if(selected >= 0 && selected < values.length) { + selectedString = values[selected]; + } + + RenderUtils.drawFloatingRectDark(left, top, dropdownWidth, 14, false); + TextRenderUtils.drawStringScaled("\u25BC", fr, left+dropdownWidth-10, y+height-7-15, false, 0xffa0a0a0, 2); + + TextRenderUtils.drawStringScaledMaxWidth(selectedString, fr, left+3, top+3, false, + dropdownWidth-16, 0xffa0a0a0); + } + } + + @Override + public void renderOverlay(int x, int y, int width) { + if(open) { + String selectedString = " - Select - "; + if(selected >= 0 && selected < values.length) { + selectedString = values[selected]; + } + + int height = getHeight(); + + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + int dropdownWidth = Math.min(width/3-10, 80); + int left = x+width/6-dropdownWidth/2; + int top = y+height-7-14; + + int dropdownHeight = 13 + 12*values.length; + + int main = 0xff202026; + int blue = 0xff2355ad; + Gui.drawRect(left, top, left+1, top+dropdownHeight, blue); //Left + Gui.drawRect(left+1, top, left+dropdownWidth, top+1, blue); //Top + Gui.drawRect(left+dropdownWidth-1, top+1, left+dropdownWidth, top+dropdownHeight, blue); //Right + Gui.drawRect(left+1, top+dropdownHeight-1, left+dropdownWidth-1, top+dropdownHeight, blue); //Bottom + Gui.drawRect(left+1, top+1, left+dropdownWidth-1, top+dropdownHeight-1, main); //Middle + + Gui.drawRect(left+1, top+14-1, left+dropdownWidth-1, top+14, blue); //Bar + + int dropdownY = 13; + for(String option : values) { + if(option.isEmpty()) { + option = "<NONE>"; + } + TextRenderUtils.drawStringScaledMaxWidth(option, fr, left+3, top+3+dropdownY, false, dropdownWidth-6, 0xffa0a0a0); + dropdownY += 12; + } + + TextRenderUtils.drawStringScaled("\u25B2", fr, left+dropdownWidth-10, y+height-7-15, false, 0xffa0a0a0, 2); + + + TextRenderUtils.drawStringScaledMaxWidth(selectedString, fr, left+3, top+3, false, + dropdownWidth-16, 0xffa0a0a0); + } + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + + int left = x+width/6-40; + int top = y+height-7-14; + + if(Mouse.getEventButtonState() && Mouse.getEventButton() == 0) { + if(mouseX >= left && mouseX <= left+80 && + mouseY >= top && mouseY <= top+14) { + open = !open; + return true; + } + } + + return false; + } + + @Override + public boolean mouseInputOverlay(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + + int left = x+width/6-40; + int top = y+height-7-14; + + if(Mouse.getEventButtonState() && Mouse.getEventButton() == 0) { + if(!(mouseX >= left && mouseX <= left+80 && + mouseY >= top && mouseY <= top+14) && open) { + open = false; + if(mouseX >= left && mouseX <= left+80) { + int dropdownY = 13; + for(int ordinal=0; ordinal < values.length; ordinal++) { + if(mouseY >= top+3+dropdownY && mouseY <= top+3+dropdownY+12) { + selected = ordinal; + if(useOrdinal) { + option.set(selected); + } else { + option.set(values[selected]); + } + return true; + } + dropdownY += 12; + } + } + return true; + } + } + + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorSlider.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorSlider.java new file mode 100644 index 0000000..a37b952 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorSlider.java @@ -0,0 +1,132 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.GuiElementBoolean; +import com.thatgravyboat.skyblockhud.core.GuiElementTextField; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.GuiElementSlider; +import net.minecraft.client.Minecraft; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; + +public class GuiOptionEditorSlider extends GuiOptionEditor { + + private final GuiElementSlider slider; + private final GuiElementTextField textField; + + public GuiOptionEditorSlider(ConfigProcessor.ProcessedOption option, float minValue, float maxValue, float minStep) { + super(option); + if(minStep < 0) minStep = 0.01f; + + float floatVal = ((Number)option.get()).floatValue(); + { + String strVal; + if(floatVal % 1 == 0) { + strVal = Integer.toString((int)floatVal); + } else { + strVal = Float.toString(floatVal); + } + textField = new GuiElementTextField(strVal, + GuiElementTextField.NO_SPACE | GuiElementTextField.NUM_ONLY | GuiElementTextField.SCALE_TEXT); + } + + slider = new GuiElementSlider(0, 0, 80, minValue, maxValue, minStep, floatVal, (val) -> { + option.set(val); + + String strVal; + if(val % 1 == 0) { + strVal = Integer.toString(val.intValue()); + } else { + strVal = Float.toString(val); + strVal = strVal.replaceAll("(\\.\\d\\d\\d)(?:\\d)+", "$1"); + strVal = strVal.replaceAll("0+$", ""); + } + textField.setText(strVal); + }); + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + int height = getHeight(); + + int fullWidth = Math.min(width/3-10, 80); + int sliderWidth = (fullWidth-5)*3/4; + int textFieldWidth = (fullWidth-5)/4; + + slider.x = x+width/6-fullWidth/2; + slider.y = y+height-7-14; + slider.width = sliderWidth; + slider.render(); + + if(textField.getFocus()) { + textField.setOptions(GuiElementTextField.NO_SPACE | GuiElementTextField.NUM_ONLY); + textField.setSize(Minecraft.getMinecraft().fontRendererObj.getStringWidth(textField.getText())+10, + 16); + } else { + textField.setSize(textFieldWidth, 16); + textField.setOptions(GuiElementTextField.NO_SPACE | GuiElementTextField.NUM_ONLY | GuiElementTextField.SCALE_TEXT); + } + + textField.render(x+width/6-fullWidth/2+sliderWidth+5, y+height-7-14); + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + + int fullWidth = Math.min(width/3-10, 80); + int sliderWidth = (fullWidth-5)*3/4; + int textFieldWidth = (fullWidth-5)/4; + + slider.x = x+width/6-fullWidth/2; + slider.y = y+height-7-14; + slider.width = sliderWidth; + if(slider.mouseInput(mouseX, mouseY)) { + textField.unfocus(); + return true; + } + + if(textField.getFocus()) { + textFieldWidth = Minecraft.getMinecraft().fontRendererObj.getStringWidth(textField.getText())+10; + } + + int textFieldX = x+width/6-fullWidth/2+sliderWidth+5; + int textFieldY = y+height-7-14; + textField.setSize(textFieldWidth, 16); + + if(Mouse.getEventButtonState() && (Mouse.getEventButton() == 0 || Mouse.getEventButton() == 1)) { + if(mouseX > textFieldX && mouseX < textFieldX+textFieldWidth && + mouseY > textFieldY && mouseY < textFieldY+16) { + textField.mouseClicked(mouseX, mouseY, Mouse.getEventButton()); + return true; + } + textField.unfocus(); + } + + return false; + } + + @Override + public boolean keyboardInput() { + if(Keyboard.getEventKeyState() && textField.getFocus()) { + textField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey()); + + try { + textField.setCustomBorderColour(0xffffffff); + float f = Float.parseFloat(textField.getText()); + if(option.set(f)) { + slider.setValue(f); + } else { + textField.setCustomBorderColour(0xff0000ff); + } + } catch(Exception e) { + textField.setCustomBorderColour(0xffff0000); + } + + return true; + } + return false; + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorText.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorText.java new file mode 100644 index 0000000..e42d5b3 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiOptionEditorText.java @@ -0,0 +1,84 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.core.GuiElementBoolean; +import com.thatgravyboat.skyblockhud.core.GuiElementTextField; +import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; +import com.thatgravyboat.skyblockhud.core.util.GuiElementSlider; +import net.minecraft.client.Minecraft; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; + +public class GuiOptionEditorText extends GuiOptionEditor { + + private final GuiElementTextField textField; + + public GuiOptionEditorText(ConfigProcessor.ProcessedOption option) { + super(option); + + textField = new GuiElementTextField((String)option.get(), 0); + } + + @Override + public void render(int x, int y, int width) { + super.render(x, y, width); + int height = getHeight(); + + int fullWidth = Math.min(width/3-10, 80); + + int textFieldX = x+width/6-fullWidth/2; + if(textField.getFocus()) { + fullWidth = Math.max(fullWidth, Minecraft.getMinecraft().fontRendererObj.getStringWidth(textField.getText())+10); + } + + textField.setSize(fullWidth, 16); + + textField.render(textFieldX, y+height-7-14); + } + + @Override + public boolean mouseInput(int x, int y, int width, int mouseX, int mouseY) { + int height = getHeight(); + + int fullWidth = Math.min(width/3-10, 80); + + int textFieldX = x+width/6-fullWidth/2; + + if(textField.getFocus()) { + fullWidth = Math.max(fullWidth, Minecraft.getMinecraft().fontRendererObj.getStringWidth(textField.getText())+10); + } + + int textFieldY = y+height-7-14; + textField.setSize(fullWidth, 16); + + if(Mouse.getEventButtonState() && (Mouse.getEventButton() == 0 || Mouse.getEventButton() == 1)) { + if(mouseX > textFieldX && mouseX < textFieldX+fullWidth && + mouseY > textFieldY && mouseY < textFieldY+16) { + textField.mouseClicked(mouseX, mouseY, Mouse.getEventButton()); + return true; + } + textField.unfocus(); + } + + return false; + } + + @Override + public boolean keyboardInput() { + if(Keyboard.getEventKeyState() && textField.getFocus()) { + Keyboard.enableRepeatEvents(true); + textField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey()); + + try { + textField.setCustomBorderColour(0xffffffff); + option.set(textField.getText()); + } catch(Exception e) { + textField.setCustomBorderColour(0xffff0000); + } + + return true; + } + return false; + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiPositionEditor.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiPositionEditor.java new file mode 100644 index 0000000..e178843 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/gui/GuiPositionEditor.java @@ -0,0 +1,179 @@ +package com.thatgravyboat.skyblockhud.core.config.gui; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.core.config.Position; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import org.lwjgl.input.Keyboard; +import org.lwjgl.input.Mouse; + +import java.io.IOException; + +public class GuiPositionEditor extends GuiScreen { + + private final Position position; + private Position originalPosition; + private final int elementWidth; + private final int elementHeight; + private final Runnable renderCallback; + private final Runnable positionChangedCallback; + private final Runnable closedCallback; + private boolean clicked = false; + private int grabbedX = 0; + private int grabbedY = 0; + + private int guiScaleOverride = -1; + + public GuiPositionEditor(Position position, int elementWidth, int elementHeight, + Runnable renderCallback, + Runnable positionChangedCallback, + Runnable closedCallback) { + this.position = position; + this.originalPosition = position.clone(); + this.elementWidth = elementWidth == -1 ? this.width : elementWidth; + this.elementHeight = elementHeight; + this.renderCallback = renderCallback; + this.positionChangedCallback = positionChangedCallback; + this.closedCallback = closedCallback; + } + + public GuiPositionEditor withScale(int scale) { + this.guiScaleOverride = scale; + return this; + } + + @Override + public void onGuiClosed() { + super.onGuiClosed(); + closedCallback.run(); + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + super.drawScreen(mouseX, mouseY, partialTicks); + ScaledResolution scaledResolution; + if(guiScaleOverride >= 0) { + scaledResolution = Utils.pushGuiScale(guiScaleOverride); + } else { + scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + } + + this.width = scaledResolution.getScaledWidth(); + this.height = scaledResolution.getScaledHeight(); + mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; + + drawDefaultBackground(); + + if(clicked) { + grabbedX += position.moveX(mouseX - grabbedX, elementWidth, scaledResolution); + grabbedY += position.moveY(mouseY - grabbedY, elementHeight, scaledResolution); + } + + renderCallback.run(); + + int x = position.getAbsX(scaledResolution, elementWidth); + int y = position.getAbsY(scaledResolution, elementHeight); + + if(position.isCenterX()) x -= elementWidth/2; + if(position.isCenterY()) y -= elementHeight/2; + Gui.drawRect(x, y, x+elementWidth, y+elementHeight, 0x80404040); + + if(guiScaleOverride >= 0) { + Utils.pushGuiScale(-1); + } + + scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + Utils.drawStringCentered("Position Editor", Minecraft.getMinecraft().fontRendererObj, + scaledResolution.getScaledWidth()/2f, 8, true, 0xffffff); + Utils.drawStringCentered("R to Reset - Arrow keys/mouse to move", Minecraft.getMinecraft().fontRendererObj, + scaledResolution.getScaledWidth()/2f, 18, true, 0xffffff); + } + + @Override + protected void mouseClicked(int mouseX, int mouseY, int mouseButton) throws IOException { + super.mouseClicked(mouseX, mouseY, mouseButton); + + if(mouseButton == 0) { + ScaledResolution scaledResolution; + if(guiScaleOverride >= 0) { + scaledResolution = Utils.pushGuiScale(guiScaleOverride); + } else { + scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + } + mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; + + int x = position.getAbsX(scaledResolution, elementWidth); + int y = position.getAbsY(scaledResolution, elementHeight); + if(position.isCenterX()) x -= elementWidth/2; + if(position.isCenterY()) y -= elementHeight/2; + + if(mouseX >= x && mouseY >= y && + mouseX <= x+elementWidth && mouseY <= y+elementHeight) { + clicked = true; + grabbedX = mouseX; + grabbedY = mouseY; + } + + if(guiScaleOverride >= 0) { + Utils.pushGuiScale(-1); + } + } + } + + @Override + protected void keyTyped(char typedChar, int keyCode) throws IOException { + Keyboard.enableRepeatEvents(true); + + if(keyCode == Keyboard.KEY_R) { + position.set(originalPosition); + } else if(!clicked) { + boolean shiftHeld = Keyboard.isKeyDown(Keyboard.KEY_LSHIFT) || Keyboard.isKeyDown(Keyboard.KEY_RSHIFT); + int dist = shiftHeld ? 10 : 1; + if(keyCode == Keyboard.KEY_DOWN) { + position.moveY(dist, elementHeight, new ScaledResolution(Minecraft.getMinecraft())); + } else if(keyCode == Keyboard.KEY_UP) { + position.moveY(-dist, elementHeight, new ScaledResolution(Minecraft.getMinecraft())); + } else if(keyCode == Keyboard.KEY_LEFT) { + position.moveX(-dist, elementWidth, new ScaledResolution(Minecraft.getMinecraft())); + } else if(keyCode == Keyboard.KEY_RIGHT) { + position.moveX(dist, elementWidth, new ScaledResolution(Minecraft.getMinecraft())); + } + } + super.keyTyped(typedChar, keyCode); + } + + @Override + protected void mouseReleased(int mouseX, int mouseY, int state) { + super.mouseReleased(mouseX, mouseY, state); + clicked = false; + } + + @Override + protected void mouseClickMove(int mouseX, int mouseY, int clickedMouseButton, long timeSinceLastClick) { + super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick); + + if(clicked) { + ScaledResolution scaledResolution; + if(guiScaleOverride >= 0) { + scaledResolution = Utils.pushGuiScale(guiScaleOverride); + } else { + scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + } + mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; + mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; + + grabbedX += position.moveX(mouseX - grabbedX, elementWidth, scaledResolution); + grabbedY += position.moveY(mouseY - grabbedY, elementHeight, scaledResolution); + positionChangedCallback.run(); + + if(guiScaleOverride >= 0) { + Utils.pushGuiScale(-1); + } + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/config/struct/ConfigProcessor.java b/src/main/java/com/thatgravyboat/skyblockhud/core/config/struct/ConfigProcessor.java new file mode 100644 index 0000000..aef92d8 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/config/struct/ConfigProcessor.java @@ -0,0 +1,176 @@ +package com.thatgravyboat.skyblockhud.core.config.struct; + +import com.google.gson.annotations.Expose; +import com.thatgravyboat.skyblockhud.core.config.Config; +import com.thatgravyboat.skyblockhud.core.config.annotations.*; +import com.thatgravyboat.skyblockhud.core.config.gui.*; +import com.thatgravyboat.skyblockhud.core.config.Config; + +import java.lang.reflect.Field; +import java.util.LinkedHashMap; +import java.util.List; + +public class ConfigProcessor { + + public static class ProcessedCategory { + public final String name; + public final String desc; + public final LinkedHashMap<String, ProcessedOption> options = new LinkedHashMap<>(); + + public ProcessedCategory(String name, String desc) { + this.name = name; + this.desc = desc; + } + } + + public static class ProcessedOption { + public final String name; + public final String desc; + public final int subcategoryId; + public GuiOptionEditor editor; + + public int accordionId = -1; + + private final Field field; + private final Object container; + + public ProcessedOption(String name, String desc, int subcategoryId, Field field, Object container) { + this.name = name; + this.desc = desc; + this.subcategoryId = subcategoryId; + + this.field = field; + this.container = container; + } + + public Object get() { + try { + return field.get(container); + } catch(Exception e) { + return null; + } + } + + public boolean set(Object value) { + try { + if(field.getType() == int.class && value instanceof Number) { + field.set(container, ((Number)value).intValue()); + } else { + field.set(container, value); + } + return true; + } catch(Exception e) { + e.printStackTrace(); + return false; + } + } + } + + public static LinkedHashMap<String, ProcessedCategory> create(Config config) { + LinkedHashMap<String, ProcessedCategory> processedConfig = new LinkedHashMap<>(); + for(Field categoryField : config.getClass().getDeclaredFields()) { + boolean exposePresent = categoryField.isAnnotationPresent(Expose.class); + boolean categoryPresent = categoryField.isAnnotationPresent(Category.class); + + if(exposePresent && categoryPresent) { + Object categoryObj; + try { + categoryObj = categoryField.get(config); + } catch(Exception e) { + //System.err.printf("Failed to load config category %s. Field was not accessible.\n", categoryField.getName()); + continue; + } + + Category categoryAnnotation = categoryField.getAnnotation(Category.class); + ProcessedCategory cat = new ProcessedCategory( + categoryAnnotation.name(), + categoryAnnotation.desc() + ); + processedConfig.put(categoryField.getName(), cat); + + for(Field optionField : categoryObj.getClass().getDeclaredFields()) { + boolean optionPresent = optionField.isAnnotationPresent(ConfigOption.class); + + if(optionPresent) { + ConfigOption optionAnnotation = optionField.getAnnotation(ConfigOption.class); + ProcessedOption option = new ProcessedOption( + optionAnnotation.name(), + optionAnnotation.desc(), + optionAnnotation.subcategoryId(), + optionField, + categoryObj + ); + if(optionField.isAnnotationPresent(ConfigAccordionId.class)) { + ConfigAccordionId annotation = optionField.getAnnotation(ConfigAccordionId.class); + option.accordionId = annotation.id(); + } + + GuiOptionEditor editor = null; + Class<?> optionType = optionField.getType(); + if(optionField.isAnnotationPresent(ConfigEditorButton.class)) { + ConfigEditorButton configEditorAnnotation = optionField.getAnnotation(ConfigEditorButton.class); + editor = new GuiOptionEditorButton(option, configEditorAnnotation.runnableId(), configEditorAnnotation.buttonText(), config); + } + if(optionType.isAssignableFrom(boolean.class) && + optionField.isAnnotationPresent(ConfigEditorBoolean.class)) { + editor = new GuiOptionEditorBoolean(option); + } + if(optionType.isAssignableFrom(boolean.class) && + optionField.isAnnotationPresent(ConfigEditorAccordion.class)) { + ConfigEditorAccordion configEditorAnnotation = optionField.getAnnotation(ConfigEditorAccordion.class); + editor = new GuiOptionEditorAccordion(option, configEditorAnnotation.id()); + } + if(optionType.isAssignableFrom(int.class)) { + if(optionField.isAnnotationPresent(ConfigEditorDropdown.class)) { + ConfigEditorDropdown configEditorAnnotation = optionField.getAnnotation(ConfigEditorDropdown.class); + editor = new GuiOptionEditorDropdown(option, configEditorAnnotation.values(), (int)option.get(), true); + } + } + if(optionType.isAssignableFrom(List.class)) { + if(optionField.isAnnotationPresent(ConfigEditorDraggableList.class)) { + ConfigEditorDraggableList configEditorAnnotation = optionField.getAnnotation(ConfigEditorDraggableList.class); + editor = new GuiOptionEditorDraggableList(option, configEditorAnnotation.exampleText()); + } + } + if(optionType.isAssignableFrom(String.class)) { + if(optionField.isAnnotationPresent(ConfigEditorDropdown.class)) { + ConfigEditorDropdown configEditorAnnotation = optionField.getAnnotation(ConfigEditorDropdown.class); + editor = new GuiOptionEditorDropdown(option, configEditorAnnotation.values(), + configEditorAnnotation.initialIndex(), false); + } else if(optionField.isAnnotationPresent(ConfigEditorColour.class)) { + editor = new GuiOptionEditorColour(option); + } else if(optionField.isAnnotationPresent(ConfigEditorText.class)) { + editor = new GuiOptionEditorText(option); + } + } + if(optionType.isAssignableFrom(int.class) || + optionType.isAssignableFrom(float.class) || + optionType.isAssignableFrom(double.class)) { + if(optionField.isAnnotationPresent(ConfigEditorSlider.class)) { + ConfigEditorSlider configEditorAnnotation = optionField.getAnnotation(ConfigEditorSlider.class); + editor = new GuiOptionEditorSlider(option, configEditorAnnotation.minValue(), + configEditorAnnotation.maxValue(), configEditorAnnotation.minStep()); + } + } + if(optionType.isAssignableFrom(String.class)) { + if(optionField.isAnnotationPresent(ConfigEditorDropdown.class)) { + ConfigEditorDropdown configEditorAnnotation = optionField.getAnnotation(ConfigEditorDropdown.class); + editor = new GuiOptionEditorDropdown(option, configEditorAnnotation.values(), 0,false); + } + } + if(editor == null) { + //System.err.printf("Failed to load config option %s. Could not find suitable editor.\n", optionField.getName()); + continue; + } + option.editor = editor; + cat.options.put(optionField.getName(), option); + } + } + } else if(exposePresent || categoryPresent) { + //System.err.printf("Failed to load config category %s. Both @Expose and @Category must be present.\n", categoryField.getName()); + } + } + return processedConfig; + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/GuiElementSlider.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/GuiElementSlider.java new file mode 100644 index 0000000..ee963c2 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/GuiElementSlider.java @@ -0,0 +1,123 @@ +package com.thatgravyboat.skyblockhud.core.util; + +import com.thatgravyboat.skyblockhud.Utils; +import com.thatgravyboat.skyblockhud.core.GuiElement; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import org.lwjgl.input.Mouse; +import org.lwjgl.opengl.GL11; + +import java.util.function.Consumer; + +import static com.thatgravyboat.skyblockhud.GuiTextures.*; + +public class GuiElementSlider extends GuiElement { + + public int x; + public int y; + public int width; + private static final int HEIGHT = 16; + + private float minValue; + private float maxValue; + private float minStep; + + private float value; + private Consumer<Float> setCallback; + + private boolean clicked = false; + + public GuiElementSlider(int x, int y, int width, float minValue, float maxValue, float minStep, + float value, Consumer<Float> setCallback) { + if(minStep < 0) minStep = 0.01f; + + this.x = x; + this.y = y; + this.width = width; + this.minValue = minValue; + this.maxValue = maxValue; + this.minStep = minStep; + this.value = value; + this.setCallback = setCallback; + } + + public void setValue(float value) { + this.value = value; + } + + @Override + public void render() { + final ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + int mouseX = Mouse.getX() * scaledResolution.getScaledWidth() / Minecraft.getMinecraft().displayWidth; + + float value = this.value; + if(clicked) { + value = (mouseX-x)*(maxValue-minValue)/width+minValue; + value = Math.max(minValue, Math.min(maxValue, value)); + value = Math.round(value/minStep)*minStep; + } + + float sliderAmount = Math.max(0, Math.min(1, (value-minValue)/(maxValue-minValue))); + int sliderAmountI = (int)(width*sliderAmount); + + GlStateManager.color(1f, 1f, 1f, 1f); + Minecraft.getMinecraft().getTextureManager().bindTexture(slider_on_cap); + Utils.drawTexturedRect(x, y, 4, HEIGHT, GL11.GL_NEAREST); + Minecraft.getMinecraft().getTextureManager().bindTexture(slider_off_cap); + Utils.drawTexturedRect(x+width-4, y, 4, HEIGHT, GL11.GL_NEAREST); + + if(sliderAmountI > 5) { + Minecraft.getMinecraft().getTextureManager().bindTexture(slider_on_segment); + Utils.drawTexturedRect(x+4, y, sliderAmountI-4, HEIGHT, GL11.GL_NEAREST); + } + + if(sliderAmountI < width-5) { + Minecraft.getMinecraft().getTextureManager().bindTexture(slider_off_segment); + Utils.drawTexturedRect(x+sliderAmountI, y, width-4-sliderAmountI, HEIGHT, GL11.GL_NEAREST); + } + + for(int i=1; i<4; i++) { + int notchX = x+width*i/4-1; + Minecraft.getMinecraft().getTextureManager().bindTexture(notchX > x+sliderAmountI ? slider_off_notch : slider_on_notch); + Utils.drawTexturedRect(notchX, y+(HEIGHT-4)/2f, 2, 4, GL11.GL_NEAREST); + } + + Minecraft.getMinecraft().getTextureManager().bindTexture(slider_button_new); + Utils.drawTexturedRect(x+sliderAmountI-4, y, 8, HEIGHT, GL11.GL_NEAREST); + } + + @Override + public boolean mouseInput(int mouseX, int mouseY) { + if(!Mouse.isButtonDown(0)) { + clicked = false; + } + + if(Mouse.getEventButton() == 0) { + clicked = Mouse.getEventButtonState() && mouseX > x && mouseX < x+width && mouseY > y && mouseY < y+HEIGHT; + if(clicked) { + value = (mouseX-x)*(maxValue-minValue)/width+minValue; + value = Math.max(minValue, Math.min(maxValue, value)); + value = (float)(Math.round(value/minStep)*(double)minStep); + setCallback.accept(value); + return true; + } + } + + if(!Mouse.getEventButtonState() && Mouse.getEventButton() == -1 && clicked) { + value = (mouseX-x)*(maxValue-minValue)/width+minValue; + value = Math.max(minValue, Math.min(maxValue, value)); + value = Math.round(value/minStep)*minStep; + setCallback.accept(value); + return true; + } + + return false; + } + + @Override + public boolean keyboardInput() { + return false; + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/MiscUtils.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/MiscUtils.java new file mode 100644 index 0000000..da89e75 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/MiscUtils.java @@ -0,0 +1,104 @@ +package com.thatgravyboat.skyblockhud.core.util; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.ResourceLocation; +import org.lwjgl.BufferUtils; +import org.lwjgl.input.Cursor; +import org.lwjgl.input.Mouse; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.datatransfer.StringSelection; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.IntBuffer; +import java.nio.file.Files; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +public class MiscUtils { + + public static void copyToClipboard(String str) { + Toolkit.getDefaultToolkit().getSystemClipboard() + .setContents(new StringSelection(str), null); + } + private static void unzip(InputStream src, File dest) { + //buffer for read and write data to file + byte[] buffer = new byte[1024]; + try { + ZipInputStream zis = new ZipInputStream(src); + ZipEntry ze = zis.getNextEntry(); + while(ze != null){ + if(!ze.isDirectory()) { + String fileName = ze.getName(); + File newFile = new File(dest, fileName); + //create directories for sub directories in zip + new File(newFile.getParent()).mkdirs(); + FileOutputStream fos = new FileOutputStream(newFile); + int len; + while ((len = zis.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + fos.close(); + } + //close this ZipEntry + zis.closeEntry(); + ze = zis.getNextEntry(); + } + //close last ZipEntry + zis.closeEntry(); + zis.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void recursiveDelete(File file) { + if(file.isDirectory() && !Files.isSymbolicLink(file.toPath())) { + for(File child : file.listFiles()) { + recursiveDelete(child); + } + } + file.delete(); + } + + private static String currentCursor = null; + + public static void resetCursor() { + if(currentCursor == null) { + return; + } + currentCursor = null; + try { Mouse.setNativeCursor(null); } catch(Exception ignored) {} + } + + public static void setCursor(ResourceLocation loc, int hotspotX, int hotspotY) { + if(currentCursor != null && loc.getResourcePath().equals(currentCursor)) { + return; + } + currentCursor = loc.getResourcePath(); + try { + BufferedImage image = ImageIO.read(Minecraft.getMinecraft() + .getResourceManager().getResource(loc).getInputStream()); + int maxSize = Cursor.getMaxCursorSize(); + IntBuffer buffer = BufferUtils.createIntBuffer(maxSize*maxSize); + for(int i=0; i<maxSize*maxSize; i++) { + int cursorX = i%maxSize; + int cursorY = i/maxSize; + if(cursorX >= image.getWidth() || cursorY >= image.getHeight()) { + buffer.put(0x00000000); + } else { + buffer.put(image.getRGB(cursorX, image.getHeight()-1-cursorY)); + } + } + buffer.flip(); + Mouse.setNativeCursor(new Cursor(maxSize, maxSize, hotspotX, hotspotY, 1, + buffer, null)); + } catch(Exception e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/Splitters.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/Splitters.java new file mode 100644 index 0000000..9736803 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/Splitters.java @@ -0,0 +1,10 @@ +package com.thatgravyboat.skyblockhud.core.util; + +import com.google.common.base.Splitter; + +public class Splitters { + + public static final Splitter NEWLINE_SPLITTER = Splitter.on('\n'); + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/StringUtils.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/StringUtils.java new file mode 100644 index 0000000..d8fd0e6 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/StringUtils.java @@ -0,0 +1,39 @@ +package com.thatgravyboat.skyblockhud.core.util; + +import com.google.common.collect.Sets; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; + +import java.util.Set; + +public class StringUtils { + + public static final Set<String> PROTOCOLS = Sets.newHashSet("http", "https"); + + public static String cleanColour(String in) { + return in.replaceAll("(?i)\\u00A7.", ""); + } + + public static String cleanColourNotModifiers(String in) { + return in.replaceAll("(?i)\\u00A7[0-9a-f]", "\u00A7r"); + } + + public static String trimToWidth(String str, int len) { + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + String trim = fr.trimStringToWidth(str, len); + + if(str.length() != trim.length() && !trim.endsWith(" ")) { + char next = str.charAt(trim.length()); + if(next != ' ') { + String[] split = trim.split(" "); + String last = split[split.length-1]; + if(last.length() < 8) { + trim = trim.substring(0, trim.length()-last.length()); + } + } + } + + return trim; + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpUtils.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpUtils.java new file mode 100644 index 0000000..e742ab1 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpUtils.java @@ -0,0 +1,26 @@ +package com.thatgravyboat.skyblockhud.core.util.lerp; + +public class LerpUtils { + + public static float clampZeroOne(float f) { + return Math.max(0, Math.min(1, f)); + } + + public static float sigmoid(float val) { + return (float)(1/(1 + Math.exp(-val))); + } + + private static final float sigmoidStr = 8; + private static final float sigmoidA = -1/(sigmoid(-0.5f * sigmoidStr) - sigmoid(0.5f * sigmoidStr)); + private static final float sigmoidB = sigmoidA*sigmoid(-0.5f * sigmoidStr); + public static float sigmoidZeroOne(float f) { + f = clampZeroOne(f); + return sigmoidA*sigmoid(sigmoidStr*(f-0.5f))-sigmoidB; + } + + public static float lerp(float a, float b, float amount) { + return b + (a - b) * clampZeroOne(amount); + } + + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingFloat.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingFloat.java new file mode 100644 index 0000000..4831956 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingFloat.java @@ -0,0 +1,68 @@ +package com.thatgravyboat.skyblockhud.core.util.lerp; + +public class LerpingFloat { + + private int timeSpent; + private long lastMillis; + private int timeToReachTarget; + + private float targetValue; + private float lerpValue; + + public LerpingFloat(float initialValue, int timeToReachTarget) { + this.targetValue = this.lerpValue = initialValue; + this.timeToReachTarget = timeToReachTarget; + } + + public LerpingFloat(int initialValue) { + this(initialValue, 200); + } + + public void tick() { + int lastTimeSpent = timeSpent; + this.timeSpent += System.currentTimeMillis() - lastMillis; + + float lastDistPercentToTarget = lastTimeSpent/(float)timeToReachTarget; + float distPercentToTarget = timeSpent/(float)timeToReachTarget; + float fac = (1-lastDistPercentToTarget)/lastDistPercentToTarget; + + float startValue = lerpValue - (targetValue - lerpValue)/fac; + + float dist = targetValue - startValue; + if(dist == 0) return; + + float oldLerpValue = lerpValue; + if(distPercentToTarget >= 1) { + lerpValue = targetValue; + } else { + lerpValue = startValue + dist*distPercentToTarget; + } + + if(lerpValue == oldLerpValue) { + timeSpent = lastTimeSpent; + } else { + this.lastMillis = System.currentTimeMillis(); + } + } + + public void resetTimer() { + this.timeSpent = 0; + this.lastMillis = System.currentTimeMillis(); + } + + public void setTarget(float targetValue) { + this.targetValue = targetValue; + } + + public void setValue(float value) { + this.targetValue = this.lerpValue = value; + } + + public float getValue() { + return lerpValue; + } + + public float getTarget() { + return targetValue; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingInteger.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingInteger.java new file mode 100644 index 0000000..48ae5ad --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/lerp/LerpingInteger.java @@ -0,0 +1,76 @@ +package com.thatgravyboat.skyblockhud.core.util.lerp; + +public class LerpingInteger { + + private int timeSpent; + private long lastMillis; + private int timeToReachTarget; + + private int targetValue; + private int lerpValue; + + public LerpingInteger(int initialValue, int timeToReachTarget) { + this.targetValue = this.lerpValue = initialValue; + this.timeToReachTarget = timeToReachTarget; + } + + public LerpingInteger(int initialValue) { + this(initialValue, 200); + } + + public void tick() { + int lastTimeSpent = timeSpent; + this.timeSpent += System.currentTimeMillis() - lastMillis; + + float lastDistPercentToTarget = lastTimeSpent/(float)timeToReachTarget; + float distPercentToTarget = timeSpent/(float)timeToReachTarget; + float fac = (1-lastDistPercentToTarget)/lastDistPercentToTarget; + + int startValue = lerpValue - (int)((targetValue - lerpValue)/fac); + + int dist = targetValue - startValue; + if(dist == 0) return; + + int oldLerpValue = lerpValue; + if(distPercentToTarget >= 1) { + lerpValue = targetValue; + } else { + lerpValue = startValue + (int)(dist*distPercentToTarget); + } + + if(lerpValue == oldLerpValue) { + timeSpent = lastTimeSpent; + } else { + this.lastMillis = System.currentTimeMillis(); + } + } + + public int getTimeSpent() { + return timeSpent; + } + + public void resetTimer() { + this.timeSpent = 0; + this.lastMillis = System.currentTimeMillis(); + } + + public void setTimeToReachTarget(int timeToReachTarget) { + this.timeToReachTarget = timeToReachTarget; + } + + public void setTarget(int targetValue) { + this.targetValue = targetValue; + } + + public void setValue(int value) { + this.targetValue = this.lerpValue = value; + } + + public int getValue() { + return lerpValue; + } + + public int getTarget() { + return targetValue; + } +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/RenderUtils.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/RenderUtils.java new file mode 100644 index 0000000..95d1b05 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/RenderUtils.java @@ -0,0 +1,165 @@ +package com.thatgravyboat.skyblockhud.core.util.render; + +import com.thatgravyboat.skyblockhud.core.BackgroundBlur; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.OpenGlHelper; +import net.minecraft.client.renderer.Tessellator; +import net.minecraft.client.renderer.WorldRenderer; +import net.minecraft.client.renderer.vertex.DefaultVertexFormats; +import org.lwjgl.opengl.GL11; +import org.lwjgl.opengl.GL14; + +public class RenderUtils { + + public static void drawFloatingRectDark(int x, int y, int width, int height) { + drawFloatingRectDark(x, y, width, height, true); + } + + public static void drawFloatingRectDark(int x, int y, int width, int height, boolean shadow) { + int alpha = 0xf0000000; + + if(OpenGlHelper.isFramebufferEnabled()) { + ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); + BackgroundBlur.renderBlurredBackground(15, scaledResolution.getScaledWidth(), + scaledResolution.getScaledHeight(), x, y, width, height, true); + } else { + alpha = 0xff000000; + } + + int main = alpha | 0x202026; + int light = 0xff303036; + int dark = 0xff101016; + Gui.drawRect(x, y, x+1, y+height, light); //Left + Gui.drawRect(x+1, y, x+width, y+1, light); //Top + Gui.drawRect(x+width-1, y+1, x+width, y+height, dark); //Right + Gui.drawRect(x+1, y+height-1, x+width-1, y+height, dark); //Bottom + Gui.drawRect(x+1, y+1, x+width-1, y+height-1, main); //Middle + if(shadow) { + Gui.drawRect(x+width, y+2, x+width+2, y+height+2, 0x70000000); //Right shadow + Gui.drawRect(x+2, y+height, x+width, y+height+2, 0x70000000); //Bottom shadow + } + } + + public static void drawFloatingRect(int x, int y, int width, int height) { + drawFloatingRectWithAlpha(x, y, width, height, 0xFF, true); + } + + public static void drawFloatingRectWithAlpha(int x, int y, int width, int height, int alpha, boolean shadow) { + int main = (alpha << 24) | 0xc0c0c0; + int light = (alpha << 24) | 0xf0f0f0; + int dark = (alpha << 24) | 0x909090; + Gui.drawRect(x, y, x+1, y+height, light); //Left + Gui.drawRect(x+1, y, x+width, y+1, light); //Top + Gui.drawRect(x+width-1, y+1, x+width, y+height, dark); //Right + Gui.drawRect(x+1, y+height-1, x+width-1, y+height, dark); //Bottom + Gui.drawRect(x+1, y+1, x+width-1, y+height-1, main); //Middle + if(shadow) { + Gui.drawRect(x+width, y+2, x+width+2, y+height+2, (alpha*3/5) << 24); //Right shadow + Gui.drawRect(x+2, y+height, x+width, y+height+2, (alpha*3/5) << 24); //Bottom shadow + } + } + + public static void drawTexturedModalRect(int x, int y, int textureX, int textureY, int width, int height){ + double f = 0.00390625; + double f1 = 0.00390625; + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer.pos(x + 0.0, y + height, 0.0).tex((textureX + 0.0) * f, (textureY + height) * f1).endVertex(); + worldrenderer.pos(x + width, y + height, 0.0).tex((textureX + width) * f, (textureY + height) * f1).endVertex(); + worldrenderer.pos(x + width, y + 0.0, 0.0).tex((textureX + width) * f, (textureY + 0.0) * f1).endVertex(); + worldrenderer.pos(x + 0.0, y + 0.0, 0.0).tex((textureX + 0.0) * f, (textureY + 0.0) * f1).endVertex(); + tessellator.draw(); + } + + public static void drawTexturedRect(float x, float y, float width, float height) { + drawTexturedRect(x, y, width, height, 0, 1, 0 , 1); + } + + public static void drawTexturedRect(float x, float y, float width, float height, int filter) { + drawTexturedRect(x, y, width, height, 0, 1, 0 , 1, filter); + } + + public static void drawTexturedRect(float x, float y, float width, float height, float uMin, float uMax, float vMin, float vMax) { + drawTexturedRect(x, y, width, height, uMin, uMax, vMin , vMax, GL11.GL_NEAREST); + } + + public static void drawTexturedRect(float x, float y, float width, float height, float uMin, float uMax, float vMin, float vMax, int filter) { + GlStateManager.enableBlend(); + GL14.glBlendFuncSeparate(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA, GL11.GL_ONE, GL11.GL_ONE_MINUS_SRC_ALPHA); + + drawTexturedRectNoBlend(x, y, width, height, uMin, uMax, vMin, vMax, filter); + + GlStateManager.disableBlend(); + } + + public static void drawTexturedRectNoBlend(float x, float y, float width, float height, float uMin, float uMax, float vMin, float vMax, int filter) { + GlStateManager.enableTexture2D(); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, filter); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, filter); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_TEX); + worldrenderer + .pos(x, y+height, 0.0D) + .tex(uMin, vMax).endVertex(); + worldrenderer + .pos(x+width, y+height, 0.0D) + .tex(uMax, vMax).endVertex(); + worldrenderer + .pos(x+width, y, 0.0D) + .tex(uMax, vMin).endVertex(); + worldrenderer + .pos(x, y, 0.0D) + .tex(uMin, vMin).endVertex(); + tessellator.draw(); + + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MIN_FILTER, GL11.GL_NEAREST); + GL11.glTexParameteri(GL11.GL_TEXTURE_2D, GL11.GL_TEXTURE_MAG_FILTER, GL11.GL_NEAREST); + } + + public static void drawGradientRect(int zLevel, int left, int top, int right, int bottom, int startColor, int endColor) { + float startAlpha = (float)(startColor >> 24 & 255) / 255.0F; + float startRed = (float)(startColor >> 16 & 255) / 255.0F; + float startGreen = (float)(startColor >> 8 & 255) / 255.0F; + float startBlue = (float)(startColor & 255) / 255.0F; + float endAlpha = (float)(endColor >> 24 & 255) / 255.0F; + float endRed = (float)(endColor >> 16 & 255) / 255.0F; + float endGreen = (float)(endColor >> 8 & 255) / 255.0F; + float endBlue = (float)(endColor & 255) / 255.0F; + + GlStateManager.disableTexture2D(); + GlStateManager.enableBlend(); + GlStateManager.disableAlpha(); + GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0); + GlStateManager.shadeModel(7425); + + Tessellator tessellator = Tessellator.getInstance(); + WorldRenderer worldrenderer = tessellator.getWorldRenderer(); + worldrenderer.begin(7, DefaultVertexFormats.POSITION_COLOR); + worldrenderer.pos(right, top, zLevel).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + worldrenderer.pos(left, top, zLevel).color(startRed, startGreen, startBlue, startAlpha).endVertex(); + worldrenderer.pos(left, bottom, zLevel).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + worldrenderer.pos(right, bottom, zLevel).color(endRed, endGreen, endBlue, endAlpha).endVertex(); + tessellator.draw(); + + GlStateManager.shadeModel(7424); + GlStateManager.disableBlend(); + GlStateManager.enableAlpha(); + GlStateManager.enableTexture2D(); + } + + public static void drawInnerBox(int left, int top, int width, int height){ + Gui.drawRect(left, top, left+width, top+height, 0x6008080E); //Middle + Gui.drawRect(left, top, left+1, top+height, 0xff08080E); //Left + Gui.drawRect(left, top, left+width, top+1, 0xff08080E); //Top + Gui.drawRect(left+width-1, top, left+width, top+height, 0xff28282E); //Right + Gui.drawRect(left, top+height-1, left+width, top+height, 0xff28282E); //Bottom + } + +} diff --git a/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/TextRenderUtils.java b/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/TextRenderUtils.java new file mode 100644 index 0000000..fce2f82 --- /dev/null +++ b/src/main/java/com/thatgravyboat/skyblockhud/core/util/render/TextRenderUtils.java @@ -0,0 +1,215 @@ +package com.thatgravyboat.skyblockhud.core.util.render; + +import com.thatgravyboat.skyblockhud.core.util.StringUtils; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.renderer.GlStateManager; +import net.minecraft.client.renderer.RenderHelper; +import net.minecraft.item.ItemStack; +import net.minecraft.util.EnumChatFormatting; +import org.lwjgl.opengl.GL11; + +import java.util.ArrayList; +import java.util.List; + +public class TextRenderUtils { + + public static int getCharVertLen(char c) { + if("acegmnopqrsuvwxyz".indexOf(c) >= 0) { + return 5; + } else { + return 7; + } + } + + public static float getVerticalHeight(String str) { + str = StringUtils.cleanColour(str); + float height = 0; + for(int i=0; i<str.length(); i++) { + char c = str.charAt(i); + int charHeight = getCharVertLen(c); + height += charHeight + 1.5f; + } + return height; + } + + public static void drawStringVertical(String str, FontRenderer fr, float x, float y, boolean shadow, int colour) { + String format = FontRenderer.getFormatFromString(str); + str = StringUtils.cleanColour(str); + for(int i=0; i<str.length(); i++) { + char c = str.charAt(i); + + int charHeight = getCharVertLen(c); + int charWidth = fr.getCharWidth(c); + fr.drawString(format+c, x+(5-charWidth)/2f, y-7+charHeight, colour, shadow); + + y += charHeight + 1.5f; + } + } + + public static void drawStringScaledMaxWidth(String str, FontRenderer fr, float x, float y, boolean shadow, int len, int colour) { + int strLen = fr.getStringWidth(str); + float factor = len/(float)strLen; + factor = Math.min(1, factor); + + drawStringScaled(str, fr, x, y, shadow, colour, factor); + } + + public static void drawStringCentered(String str, FontRenderer fr, float x, float y, boolean shadow, int colour) { + int strLen = fr.getStringWidth(str); + + float x2 = x - strLen/2f; + float y2 = y - fr.FONT_HEIGHT/2f; + + GL11.glTranslatef(x2, y2, 0); + fr.drawString(str, 0, 0, colour, shadow); + GL11.glTranslatef(-x2, -y2, 0); + } + + public static void drawStringScaled(String str, FontRenderer fr, float x, float y, boolean shadow, int colour, float factor) { + GlStateManager.scale(factor, factor, 1); + fr.drawString(str, x/factor, y/factor, colour, shadow); + GlStateManager.scale(1/factor, 1/factor, 1); + } + + public static void drawStringCenteredScaledMaxWidth(String str, FontRenderer fr, float x, float y, boolean shadow, int len, int colour) { + int strLen = fr.getStringWidth(str); + float factor = len/(float)strLen; + factor = Math.min(1, factor); + int newLen = Math.min(strLen, len); + + float fontHeight = 8*factor; + + drawStringScaled(str, fr, x-newLen/2, y-fontHeight/2, shadow, colour, factor); + } + + public static void renderToolTip(ItemStack stack, int mouseX, int mouseY, int screenWidth, int screenHeight, FontRenderer fontStd) { + List<String> list = stack.getTooltip(Minecraft.getMinecraft().thePlayer, + Minecraft.getMinecraft().gameSettings.advancedItemTooltips); + + for (int i = 0; i < list.size(); ++i) { + if (i == 0) { + list.set(i, stack.getRarity().rarityColor + list.get(i)); + } else { + list.set(i, EnumChatFormatting.GRAY + list.get(i)); + } + } + + FontRenderer font = stack.getItem().getFontRenderer(stack); + drawHoveringText(list, mouseX, mouseY, screenWidth, screenHeight, -1, font == null ? fontStd : font); + } + + public static void drawHoveringText(List<String> textLines, final int mouseX, final int mouseY, final int screenWidth, final int screenHeight, final int maxTextWidth, FontRenderer font) { + if (!textLines.isEmpty()) { + GlStateManager.disableRescaleNormal(); + RenderHelper.disableStandardItemLighting(); + GlStateManager.disableLighting(); + GlStateManager.disableDepth(); + int tooltipTextWidth = 0; + + for (String textLine : textLines) { + int textLineWidth = font.getStringWidth(textLine); + + if (textLineWidth > tooltipTextWidth) { + tooltipTextWidth = textLineWidth; + } + } + + boolean needsWrap = false; + + int titleLinesCount = 1; + int tooltipX = mouseX + 12; + if (tooltipX + tooltipTextWidth + 4 > screenWidth) { + tooltipX = mouseX - 16 - tooltipTextWidth; + if (tooltipX < 4) // if the tooltip doesn't fit on the screen + { + if (mouseX > screenWidth / 2) { + tooltipTextWidth = mouseX - 12 - 8; + } else { + tooltipTextWidth = screenWidth - 16 - mouseX; + } + needsWrap = true; + } + } + + if (maxTextWidth > 0 && tooltipTextWidth > maxTextWidth) { + tooltipTextWidth = maxTextWidth; + needsWrap = true; + } + + if (needsWrap) { + int wrappedTooltipWidth = 0; + List<String> wrappedTextLines = new ArrayList<String>(); + for (int i = 0; i < textLines.size(); i++) { + String textLine = textLines.get(i); + List<String> wrappedLine = font.listFormattedStringToWidth(textLine, tooltipTextWidth); + if (i == 0) { + titleLinesCount = wrappedLine.size(); + } + + for (String line : wrappedLine) { + int lineWidth = font.getStringWidth(line); + if (lineWidth > wrappedTooltipWidth) { + wrappedTooltipWidth = lineWidth; + } + wrappedTextLines.add(line); + } + } + tooltipTextWidth = wrappedTooltipWidth; + textLines = wrappedTextLines; + + if (mouseX > screenWidth / 2) { + tooltipX = mouseX - 16 - tooltipTextWidth; + } else { + tooltipX = mouseX + 12; + } + } + + int tooltipY = mouseY - 12; + int tooltipHeight = 8; + + if (textLines.size() > 1) { + tooltipHeight += (textLines.size() - 1) * 10; + if (textLines.size() > titleLinesCount) { + tooltipHeight += 2; // gap between title lines and next lines + } + } + + if (tooltipY + tooltipHeight + 6 > screenHeight) { + tooltipY = screenHeight - tooltipHeight - 6; + } + + final int zLevel = 300; + final int backgroundColor = 0xF0100010; + RenderUtils.drawGradientRect(zLevel, tooltipX - 3, tooltipY - 4, tooltipX + tooltipTextWidth + 3, tooltipY - 3, backgroundColor, backgroundColor); + RenderUtils.drawGradientRect(zLevel, tooltipX - 3, tooltipY + tooltipHeight + 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 4, backgroundColor, backgroundColor); + RenderUtils.drawGradientRect(zLevel, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); + RenderUtils.drawGradientRect(zLevel, tooltipX - 4, tooltipY - 3, tooltipX - 3, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); + RenderUtils.drawGradientRect(zLevel, tooltipX + tooltipTextWidth + 3, tooltipY - 3, tooltipX + tooltipTextWidth + 4, tooltipY + tooltipHeight + 3, backgroundColor, backgroundColor); + final int borderColorStart = 0x505000FF; + final int borderColorEnd = (borderColorStart & 0xFEFEFE) >> 1 | borderColorStart & 0xFF000000; + RenderUtils.drawGradientRect(zLevel, tooltipX - 3, tooltipY - 3 + 1, tooltipX - 3 + 1, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); + RenderUtils.drawGradientRect(zLevel, tooltipX + tooltipTextWidth + 2, tooltipY - 3 + 1, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3 - 1, borderColorStart, borderColorEnd); + RenderUtils.drawGradientRect(zLevel, tooltipX - 3, tooltipY - 3, tooltipX + tooltipTextWidth + 3, tooltipY - 3 + 1, borderColorStart, borderColorStart); + RenderUtils.drawGradientRect(zLevel, tooltipX - 3, tooltipY + tooltipHeight + 2, tooltipX + tooltipTextWidth + 3, tooltipY + tooltipHeight + 3, borderColorEnd, borderColorEnd); + + for (int lineNumber = 0; lineNumber < textLines.size(); ++lineNumber) { + String line = textLines.get(lineNumber); + font.drawStringWithShadow(line, (float) tooltipX, (float) tooltipY, -1); + + if (lineNumber + 1 == titleLinesCount) { + tooltipY += 2; + } + + tooltipY += 10; + } + + GlStateManager.enableLighting(); + GlStateManager.enableDepth(); + RenderHelper.enableStandardItemLighting(); + GlStateManager.enableRescaleNormal(); + } + GlStateManager.disableLighting(); + } + +} |