package com.thatgravyboat.skyblockhud.config; import com.google.common.collect.Lists; import com.thatgravyboat.skyblockhud.core.GlScissorStack; import com.thatgravyboat.skyblockhud.core.GuiElement; import com.thatgravyboat.skyblockhud.core.config.Config; import com.thatgravyboat.skyblockhud.core.config.gui.GuiOptionEditor; import com.thatgravyboat.skyblockhud.core.config.gui.GuiOptionEditorAccordion; import com.thatgravyboat.skyblockhud.core.config.struct.ConfigProcessor; import com.thatgravyboat.skyblockhud.core.util.lerp.LerpUtils; import com.thatgravyboat.skyblockhud.core.util.lerp.LerpingInteger; 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.awt.*; import java.net.URI; import java.util.*; import java.util.List; import static com.thatgravyboat.skyblockhud.GuiTextures.*; public class SBHConfigEditor extends GuiElement { private static final ResourceLocation[] socialsIco = new ResourceLocation[] { DISCORD, TWITTER }; private static final String[] socialsLink = new String[] { "https://discord.gg/moulberry", "https://twitter.com/thatgravytboat/" }; private final long openedMillis; private String selectedCategory = null; private final LerpingInteger optionsScroll = new LerpingInteger(0, 150); private final LerpingInteger categoryScroll = new LerpingInteger(0, 150); private LinkedHashMap processedConfig; private HashMap categoryForOption = new HashMap<>(); public SBHConfigEditor(Config config) { this(config, null); } public SBHConfigEditor(Config config, String categoryOpen) { this.openedMillis = System.currentTimeMillis(); this.processedConfig = ConfigProcessor.create(config); for(ConfigProcessor.ProcessedCategory category : processedConfig.values()) { for(ConfigProcessor.ProcessedOption option : category.options.values()) { categoryForOption.put(option, category); } } if(categoryOpen != null) { for(Map.Entry category : processedConfig.entrySet()) { if(category.getValue().name.equalsIgnoreCase(categoryOpen)) { selectedCategory = category.getKey(); break; } } if(selectedCategory == null) { for(Map.Entry category : processedConfig.entrySet()) { if(category.getValue().name.toLowerCase().startsWith(categoryOpen.toLowerCase())) { selectedCategory = category.getKey(); break; } } } if(selectedCategory == null) { for(Map.Entry category : processedConfig.entrySet()) { if(category.getValue().name.toLowerCase().contains(categoryOpen.toLowerCase())) { selectedCategory = category.getKey(); break; } } } } } private LinkedHashMap getCurrentConfigEditing() { return new LinkedHashMap<>(processedConfig); } private LinkedHashMap getOptionsInCategory(ConfigProcessor.ProcessedCategory cat) { return new LinkedHashMap<>(cat.options); } public String getSelectedCategory() { return selectedCategory; } public String getSelectedCategoryName() { return processedConfig.get(selectedCategory).name; } private void setSelectedCategory(String category) { selectedCategory = category; optionsScroll.setValue(0); } public void render() { optionsScroll.tick(); categoryScroll.tick(); List tooltipToDisplay = null; long currentTime = System.currentTimeMillis(); long delta = currentTime - openedMillis; ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); int width = scaledResolution.getScaledWidth(); int height = scaledResolution.getScaledHeight(); int mouseX = Mouse.getX() * width / Minecraft.getMinecraft().displayWidth; int mouseY = height - Mouse.getY() * height / Minecraft.getMinecraft().displayHeight - 1; float opacityFactor = LerpUtils.sigmoidZeroOne(delta/500f); RenderUtils.drawGradientRect(0, 0, 0, width, height, (int)(0x80*opacityFactor) << 24 | 0x101010, (int)(0x90*opacityFactor) << 24 | 0x101010); int xSize = Math.min(scaledResolution.getScaledWidth()-100/scaledResolution.getScaleFactor(), 500); int ySize = Math.min(scaledResolution.getScaledHeight()-100/scaledResolution.getScaleFactor(), 400); int x = (scaledResolution.getScaledWidth() - xSize)/2; int y = (scaledResolution.getScaledHeight() - ySize)/2; int adjScaleFactor = Math.max(2, scaledResolution.getScaleFactor()); int openingXSize = xSize; int openingYSize = ySize; if(delta < 150) { openingXSize = (int)(delta*xSize/150); openingYSize = 5; } else if(delta < 300) { openingYSize = 5 + (int)(delta-150)*(ySize-5)/150; } RenderUtils.drawFloatingRectDark( (scaledResolution.getScaledWidth() - openingXSize)/2, (scaledResolution.getScaledHeight() - openingYSize)/2, openingXSize, openingYSize); GlScissorStack.clear(); GlScissorStack.push((scaledResolution.getScaledWidth() - openingXSize)/2, (scaledResolution.getScaledHeight() - openingYSize)/2, (scaledResolution.getScaledWidth() + openingXSize)/2, (scaledResolution.getScaledHeight() + openingYSize)/2, scaledResolution); RenderUtils.drawFloatingRectDark(x+5, y+5, xSize-10, 20, false); FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; TextRenderUtils.drawStringCenteredScaledMaxWidth("SkyBlockHud by "+EnumChatFormatting.RED+"ThatGravyBoat"+EnumChatFormatting.RESET+", config by "+EnumChatFormatting.DARK_PURPLE+"Moulberry", fr, x+xSize/2f, y+15, false, 200, 0xa0a0a0); RenderUtils.drawFloatingRectDark(x+4, y+49-20, 140, ySize-54+20, false); int innerPadding = 20/adjScaleFactor; int innerLeft = x+4+innerPadding; int innerRight = x+144-innerPadding; int innerTop = y+49+innerPadding; int innerBottom = y+ySize-5-innerPadding; Gui.drawRect(innerLeft, innerTop, innerLeft+1, innerBottom, 0xff08080E); //Left Gui.drawRect(innerLeft+1, innerTop, innerRight, innerTop+1, 0xff08080E); //Top Gui.drawRect(innerRight-1, innerTop+1, innerRight, innerBottom, 0xff28282E); //Right Gui.drawRect(innerLeft+1, innerBottom-1, innerRight-1, innerBottom, 0xff28282E); //Bottom Gui.drawRect(innerLeft+1, innerTop+1, innerRight-1, innerBottom-1, 0x6008080E); //Middle GlScissorStack.push(0, innerTop+1, scaledResolution.getScaledWidth(), innerBottom-1, scaledResolution); float catBarSize = 1; int catY = -categoryScroll.getValue(); LinkedHashMap currentConfigEditing = getCurrentConfigEditing(); for(Map.Entry entry : currentConfigEditing.entrySet()) { String selectedCategory = getSelectedCategory(); if(selectedCategory == null || !currentConfigEditing.containsKey(selectedCategory)) { setSelectedCategory(entry.getKey()); } String catName = entry.getValue().name; if(entry.getKey().equals(getSelectedCategory())) { catName = EnumChatFormatting.DARK_AQUA.toString() + EnumChatFormatting.UNDERLINE + catName; } else { catName = EnumChatFormatting.GRAY + catName; } TextRenderUtils.drawStringCenteredScaledMaxWidth(catName, fr, x+75, y+70+catY, false, 100, -1); catY += 15; if(catY > 0) { catBarSize = LerpUtils.clampZeroOne((float)(innerBottom-innerTop-2)/(catY+5+categoryScroll.getValue())); } } float catBarStart = categoryScroll.getValue() / (float)(catY + categoryScroll.getValue()); float catBarEnd = catBarStart+catBarSize; if(catBarEnd > 1) { catBarEnd = 1; if(categoryScroll.getTarget()/(float)(catY + categoryScroll.getValue())+catBarSize < 1) { int target = optionsScroll.getTarget(); categoryScroll.setValue((int)Math.ceil((catY+5+categoryScroll.getValue())-catBarSize*(catY+5+categoryScroll.getValue()))); categoryScroll.setTarget(target); } else { categoryScroll.setValue((int)Math.ceil((catY+5+categoryScroll.getValue())-catBarSize*(catY+5+categoryScroll.getValue()))); } } int catDist = innerBottom-innerTop-12; Gui.drawRect(innerLeft+2, innerTop+5, innerLeft+7, innerBottom-5, 0xff101010); Gui.drawRect(innerLeft+3, innerTop+6+(int)(catDist*catBarStart), innerLeft+6, innerTop+6+(int)(catDist*catBarEnd), 0xff303030); GlScissorStack.pop(scaledResolution); TextRenderUtils.drawStringCenteredScaledMaxWidth("Categories", fr, x+75, y+44, false, 120, 0xa368ef); RenderUtils.drawFloatingRectDark(x+149, y+29, xSize-154, ySize-34, false); innerLeft = x+149+innerPadding; innerRight =x+xSize-5-innerPadding; innerBottom = y+ySize-5-innerPadding; GlStateManager.color(1, 1, 1, 1); int rightStuffLen = 20; if(getSelectedCategory() != null && currentConfigEditing.containsKey(getSelectedCategory())) { ConfigProcessor.ProcessedCategory cat = currentConfigEditing.get(getSelectedCategory()); TextRenderUtils.drawStringScaledMaxWidth(cat.desc, fr, innerLeft+5, y+40, true, innerRight-innerLeft-rightStuffLen-10, 0xb0b0b0); } Gui.drawRect(innerLeft, innerTop, innerLeft+1, innerBottom, 0xff08080E); //Left Gui.drawRect(innerLeft+1, innerTop, innerRight, innerTop+1, 0xff08080E); //Top Gui.drawRect(innerRight-1, innerTop+1, innerRight, innerBottom, 0xff303036); //Right Gui.drawRect(innerLeft+1, innerBottom-1, innerRight-1, innerBottom, 0xff303036); //Bottom Gui.drawRect(innerLeft+1, innerTop+1, innerRight-1, innerBottom-1, 0x6008080E); //Middle GlScissorStack.push(innerLeft+1, innerTop+1, innerRight-1, innerBottom-1, scaledResolution); float barSize = 1; int optionY = -optionsScroll.getValue(); if(getSelectedCategory() != null && currentConfigEditing.containsKey(getSelectedCategory())) { ConfigProcessor.ProcessedCategory cat = currentConfigEditing.get(getSelectedCategory()); int optionWidthDefault = innerRight-innerLeft-20; GlStateManager.enableDepth(); Set activeAccordions = new HashSet<>(); for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { int optionWidth = optionWidthDefault; if(option.accordionId >= 0) { if(!activeAccordions.contains(option.accordionId)) { continue; } optionWidth = optionWidthDefault - 2*innerPadding; } GuiOptionEditor editor = option.editor; if(editor == null) { continue; } if(editor instanceof GuiOptionEditorAccordion) { GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; if(accordion.getToggled()) { activeAccordions.add(accordion.getAccordionId()); } } int optionHeight = editor.getHeight(); if(innerTop+5+optionY+optionHeight > innerTop+1 && innerTop+5+optionY < innerBottom-1) { editor.render((innerLeft+innerRight-optionWidth)/2-5, innerTop+5+optionY, optionWidth); } optionY += optionHeight + 5; } GlStateManager.disableDepth(); if(optionY > 0) { barSize = LerpUtils.clampZeroOne((float)(innerBottom-innerTop-2)/(optionY+5+optionsScroll.getValue())); } } GlScissorStack.pop(scaledResolution); GL11.glDisable(GL11.GL_SCISSOR_TEST); if(getSelectedCategory() != null && currentConfigEditing.containsKey(getSelectedCategory())) { int optionYOverlay = -optionsScroll.getValue(); ConfigProcessor.ProcessedCategory cat = currentConfigEditing.get(getSelectedCategory()); int optionWidthDefault = innerRight-innerLeft-20; GlStateManager.translate(0, 0, 10); GlStateManager.enableDepth(); Set activeAccordions = new HashSet<>(); for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { int optionWidth = optionWidthDefault; if(option.accordionId >= 0) { if(!activeAccordions.contains(option.accordionId)) { continue; } optionWidth = optionWidthDefault - 2*innerPadding; } GuiOptionEditor editor = option.editor; if(editor == null) { continue; } if(editor instanceof GuiOptionEditorAccordion) { GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; if(accordion.getToggled()) { activeAccordions.add(accordion.getAccordionId()); } } int optionHeight = editor.getHeight(); if(innerTop+5+optionYOverlay+optionHeight > innerTop+1 && innerTop+5+optionYOverlay < innerBottom-1) { editor.renderOverlay((innerLeft+innerRight-optionWidth)/2-5, innerTop+5+optionYOverlay, optionWidth); } optionYOverlay += optionHeight + 5; } GlStateManager.disableDepth(); GlStateManager.translate(0, 0, -10); } GL11.glEnable(GL11.GL_SCISSOR_TEST); float barStart = optionsScroll.getValue() / (float)(optionY + optionsScroll.getValue()); float barEnd = barStart+barSize; if(barEnd > 1) { barEnd = 1; if(optionsScroll.getTarget()/(float)(optionY + optionsScroll.getValue())+barSize < 1) { int target = optionsScroll.getTarget(); optionsScroll.setValue((int)Math.ceil((optionY+5+optionsScroll.getValue())-barSize*(optionY+5+optionsScroll.getValue()))); optionsScroll.setTarget(target); } else { optionsScroll.setValue((int)Math.ceil((optionY+5+optionsScroll.getValue())-barSize*(optionY+5+optionsScroll.getValue()))); } } int dist = innerBottom-innerTop-12; Gui.drawRect(innerRight-10, innerTop+5, innerRight-5, innerBottom-5, 0xff101010); Gui.drawRect(innerRight-9, innerTop+6+(int)(dist*barStart), innerRight-6, innerTop+6+(int)(dist*barEnd), 0xff303030); for(int socialIndex=0; socialIndex= socialLeft && mouseX <= socialLeft+16 && mouseY >= y+6 && mouseY <= y+23) { tooltipToDisplay = Lists.newArrayList(EnumChatFormatting.YELLOW+"Go to: "+EnumChatFormatting.RESET+socialsLink[socialIndex]); } } GlScissorStack.clear(); if(tooltipToDisplay != null) { TextRenderUtils.drawHoveringText(tooltipToDisplay, mouseX, mouseY, width, height, -1, fr); } GlStateManager.translate(0, 0, -2); } public boolean mouseInput(int mouseX, int mouseY) { ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); int width = scaledResolution.getScaledWidth(); int height = scaledResolution.getScaledHeight(); int xSize = Math.min(width-100/scaledResolution.getScaleFactor(), 500); int ySize = Math.min(height-100/scaledResolution.getScaleFactor(), 400); int x = (scaledResolution.getScaledWidth() - xSize)/2; int y = (scaledResolution.getScaledHeight() - ySize)/2; int adjScaleFactor = Math.max(2, scaledResolution.getScaleFactor()); int innerPadding = 20/adjScaleFactor; int innerTop = y+49+innerPadding; int innerBottom = y+ySize-5-innerPadding; int innerLeft = x+149+innerPadding; int innerRight = x+xSize-5-innerPadding; int dWheel = Mouse.getEventDWheel(); if(mouseY > innerTop && mouseY < innerBottom && dWheel != 0) { if(dWheel < 0) { dWheel = -1; } if(dWheel > 0) { dWheel = 1; } if(mouseX < innerLeft) { int newTarget = categoryScroll.getTarget() - dWheel*30; if(newTarget < 0) { newTarget = 0; } float catBarSize = 1; int catY = -newTarget; for(Map.Entry entry : getCurrentConfigEditing().entrySet()) { if(getSelectedCategory() == null) { setSelectedCategory(entry.getKey()); } catY += 15; if(catY > 0) { catBarSize = LerpUtils.clampZeroOne((float)(innerBottom-innerTop-2)/(catY+5+newTarget)); } } int barMax = (int)Math.floor((catY+5+newTarget)-catBarSize*(catY+5+newTarget)); if(newTarget > barMax) { newTarget = barMax; } categoryScroll.resetTimer(); categoryScroll.setTarget(newTarget); } else { int newTarget = optionsScroll.getTarget() - dWheel*30; if(newTarget < 0) { newTarget = 0; } float barSize = 1; int optionY = -newTarget; if(getSelectedCategory() != null && getCurrentConfigEditing() != null && getCurrentConfigEditing().containsKey(getSelectedCategory())) { ConfigProcessor.ProcessedCategory cat = getCurrentConfigEditing().get(getSelectedCategory()); Set activeAccordions = new HashSet<>(); for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { if(option.accordionId >= 0) { if(!activeAccordions.contains(option.accordionId)) { continue; } } GuiOptionEditor editor = option.editor; if(editor == null) { continue; } if(editor instanceof GuiOptionEditorAccordion) { GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; if(accordion.getToggled()) { activeAccordions.add(accordion.getAccordionId()); } } optionY += editor.getHeight() + 5; if(optionY > 0) { barSize = LerpUtils.clampZeroOne((float)(innerBottom-innerTop-2)/(optionY+5 + newTarget)); } } } int barMax = (int)Math.floor((optionY+5+newTarget)-barSize*(optionY+5+newTarget)); if(newTarget > barMax) { newTarget = barMax; } optionsScroll.setTimeToReachTarget(Math.min(150, Math.max(10, 5*Math.abs(newTarget - optionsScroll.getValue())))); optionsScroll.resetTimer(); optionsScroll.setTarget(newTarget); } } else if(Mouse.getEventButtonState() && Mouse.getEventButton() == 0) { if(getCurrentConfigEditing() != null) { int catY = -categoryScroll.getValue(); for(Map.Entry entry : getCurrentConfigEditing().entrySet()) { if(getSelectedCategory() == null) { setSelectedCategory(entry.getKey()); } if(mouseX >= x+5 && mouseX <= x+145 && mouseY >= y+70+catY-7 && mouseY <= y+70+catY+7) { setSelectedCategory(entry.getKey()); return true; } catY += 15; } } for(int socialIndex=0; socialIndex= socialLeft && mouseX <= socialLeft+16 && mouseY >= y+6 && mouseY <= y+23) { try { Desktop.getDesktop().browse(new URI(socialsLink[socialIndex])); } catch(Exception ignored) {} return true; } } } int optionY = -optionsScroll.getValue(); if(getSelectedCategory() != null && getCurrentConfigEditing() != null && getCurrentConfigEditing().containsKey(getSelectedCategory())) { int optionWidthDefault = innerRight-innerLeft-20; ConfigProcessor.ProcessedCategory cat = getCurrentConfigEditing().get(getSelectedCategory());Set activeAccordions = new HashSet<>(); for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { int optionWidth = optionWidthDefault; if(option.accordionId >= 0) { if(!activeAccordions.contains(option.accordionId)) { continue; } optionWidth = optionWidthDefault - 2*innerPadding; } GuiOptionEditor editor = option.editor; if(editor == null) { continue; } if(editor instanceof GuiOptionEditorAccordion) { GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; if(accordion.getToggled()) { activeAccordions.add(accordion.getAccordionId()); } } if(editor.mouseInputOverlay((innerLeft+innerRight-optionWidth)/2-5, innerTop+5+optionY, optionWidth, mouseX, mouseY)) { return true; } optionY += editor.getHeight() + 5; } } if(mouseX > innerLeft && mouseX < innerRight && mouseY > innerTop && mouseY < innerBottom) { optionY = -optionsScroll.getValue(); if(getSelectedCategory() != null && getCurrentConfigEditing() != null && getCurrentConfigEditing().containsKey(getSelectedCategory())) { int optionWidthDefault = innerRight-innerLeft-20; ConfigProcessor.ProcessedCategory cat = getCurrentConfigEditing().get(getSelectedCategory()); Set activeAccordions = new HashSet<>(); for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { int optionWidth = optionWidthDefault; if(option.accordionId >= 0) { if(!activeAccordions.contains(option.accordionId)) { continue; } optionWidth = optionWidthDefault - 2*innerPadding; } GuiOptionEditor editor = option.editor; if(editor == null) { continue; } if(editor instanceof GuiOptionEditorAccordion) { GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; if(accordion.getToggled()) { activeAccordions.add(accordion.getAccordionId()); } } if(editor.mouseInput((innerLeft+innerRight-optionWidth)/2-5, innerTop+5+optionY, optionWidth, mouseX, mouseY)) { return true; } optionY += editor.getHeight() + 5; } } } return true; } public boolean keyboardInput() { ScaledResolution scaledResolution = new ScaledResolution(Minecraft.getMinecraft()); int width = scaledResolution.getScaledWidth(); int xSize = Math.min(width-100/scaledResolution.getScaleFactor(), 500); int adjScaleFactor = Math.max(2, scaledResolution.getScaleFactor()); int innerPadding = 20/adjScaleFactor; int innerWidth = xSize-154-innerPadding*2; if(getSelectedCategory() != null && getCurrentConfigEditing() != null && getCurrentConfigEditing().containsKey(getSelectedCategory())) { ConfigProcessor.ProcessedCategory cat = getCurrentConfigEditing().get(getSelectedCategory()); Set activeAccordions = new HashSet<>(); for(ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) { if(option.accordionId >= 0) { if(!activeAccordions.contains(option.accordionId)) { continue; } } GuiOptionEditor editor = option.editor; if(editor == null) { continue; } if(editor instanceof GuiOptionEditorAccordion) { GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor; if(accordion.getToggled()) { activeAccordions.add(accordion.getAccordionId()); } } if(editor.keyboardInput()) { return true; } } } return true; } }