/*
* Copyright (C) 2022 NotEnoughUpdates contributors
*
* This file is part of NotEnoughUpdates.
*
* NotEnoughUpdates is free software: you can redistribute it
* and/or modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 of the License, or (at your option) any later version.
*
* NotEnoughUpdates is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with NotEnoughUpdates. If not, see .
*/
package at.hannibal2.skyhanni.config;
import at.hannibal2.skyhanni.SkyHanniMod;
import at.hannibal2.skyhanni.config.core.GlScissorStack;
import at.hannibal2.skyhanni.config.core.GuiElement;
import at.hannibal2.skyhanni.config.core.GuiElementTextField;
import at.hannibal2.skyhanni.config.core.config.gui.GuiOptionEditor;
import at.hannibal2.skyhanni.config.core.config.gui.GuiOptionEditorAccordion;
import at.hannibal2.skyhanni.config.core.config.struct.ConfigProcessor;
import at.hannibal2.skyhanni.config.core.util.lerp.LerpUtils;
import at.hannibal2.skyhanni.config.core.util.lerp.LerpingInteger;
import at.hannibal2.skyhanni.config.core.util.render.GuiRenderUtils;
import at.hannibal2.skyhanni.config.core.util.render.TextRenderUtils;
import at.hannibal2.skyhanni.utils.StringUtils;
import com.google.common.collect.Lists;
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.Keyboard;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
import java.awt.*;
import java.net.URI;
import java.util.List;
import java.util.*;
import static at.hannibal2.skyhanni.config.GuiTextures.DISCORD;
import static at.hannibal2.skyhanni.config.GuiTextures.GITHUB;
public class ConfigEditor extends GuiElement {
private static final ResourceLocation[] socialsIco = new ResourceLocation[]{
DISCORD, GITHUB
};
private static final String[] socialsLink = new String[]{
"https://discord.gg/8DXVN4BJz3",
"https://github.com/hannibal002/SkyHanni"
};
private static final ResourceLocation SEARCH_ICON = new ResourceLocation("notenoughupdates:core/search.png");
public static ConfigEditor editor = new ConfigEditor(SkyHanniMod.feature);
private final long openedMillis;
private final LerpingInteger optionsScroll = new LerpingInteger(0, 150);
private final LerpingInteger categoryScroll = new LerpingInteger(0, 150);
private final LinkedHashMap processedConfig;
private final TreeMap> searchOptionMap = new TreeMap<>();
private final HashMap categoryForOption =
new HashMap<>();
private final LerpingInteger minimumSearchSize = new LerpingInteger(0, 150);
private final GuiElementTextField searchField = new GuiElementTextField("", 0, 20, 0);
private String selectedCategory = null;
private Set searchedCategories = null;
private Map> searchedAccordions = null;
private Set searchedOptions = null;
private float optionsBarStart;
private float optionsBarend;
private int lastMouseX = 0;
private int keyboardScrollXCutoff = 0;
public ConfigEditor(Features config) {
this(config, null);
}
public ConfigEditor(Features 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);
String combined = category.name + " " + category.desc + " " + option.name + " " + option.desc;
combined = combined.replaceAll("[^a-zA-Z_ ]", "").toLowerCase();
for (String word : combined.split("[ _]")) {
searchOptionMap.computeIfAbsent(word, k -> new HashSet<>()).add(option);
}
}
}
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;
}
}
}
}
editor = this;
}
private LinkedHashMap getCurrentConfigEditing() {
LinkedHashMap newMap = new LinkedHashMap<>(processedConfig);
if (searchedCategories != null) newMap.values().retainAll(searchedCategories);
return newMap;
}
private LinkedHashMap getOptionsInCategory(ConfigProcessor.ProcessedCategory cat) {
LinkedHashMap newMap = new LinkedHashMap<>(cat.options);
if (searchedOptions != null) {
Set retain = new HashSet<>();
retain.addAll(searchedOptions);
if (searchedAccordions != null) {
Set visibleAccordions = searchedAccordions.get(cat);
if (visibleAccordions != null && !visibleAccordions.isEmpty()) {
for (ConfigProcessor.ProcessedOption option : newMap.values()) {
if (option.editor instanceof GuiOptionEditorAccordion) {
int accordionId = ((GuiOptionEditorAccordion) option.editor).getAccordionId();
if (visibleAccordions.contains(accordionId)) {
retain.add(option);
}
}
}
}
}
newMap.values().retainAll(retain);
}
return newMap;
}
public String getSelectedCategory() {
return selectedCategory;
}
private void setSelectedCategory(String category) {
selectedCategory = category;
optionsScroll.setValue(0);
}
public String getSelectedCategoryName() {
return processedConfig.get(selectedCategory).name;
}
public void search() {
String search = searchField.getText().trim().replaceAll("[^a-zA-Z_ ]", "").toLowerCase();
searchedCategories = null;
searchedOptions = null;
searchedAccordions = null;
if (!search.isEmpty()) {
searchedCategories = new HashSet<>();
searchedAccordions = new HashMap<>();
for (String word : search.split(" ")) {
if (word.trim().isEmpty()) continue;
Set options = new HashSet<>();
Map> map = StringUtils.INSTANCE.subMapWithKeysThatAreSuffixes(word, searchOptionMap);
map.values().forEach(options::addAll);
if (!options.isEmpty()) {
if (searchedOptions == null) {
searchedOptions = new HashSet<>(options);
} else {
searchedOptions.retainAll(options);
}
}
}
if (searchedOptions == null) {
searchedOptions = new HashSet<>();
} else {
for (ConfigProcessor.ProcessedOption option : searchedOptions) {
ConfigProcessor.ProcessedCategory cat = categoryForOption.get(option);
if (cat == null) continue;
searchedCategories.add(cat);
searchedAccordions.computeIfAbsent(cat, k -> new HashSet<>()).add(option.accordionId);
}
}
}
}
public void render() {
optionsScroll.tick();
categoryScroll.tick();
handleKeyboardPresses();
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);
GuiRenderUtils.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;
}
GuiRenderUtils.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
);
GuiRenderUtils.drawFloatingRectDark(x + 5, y + 5, xSize - 10, 20, false);
FontRenderer fr = Minecraft.getMinecraft().fontRendererObj;
TextRenderUtils.drawStringCenteredScaledMaxWidth("SkyHanni " + SkyHanniMod.VERSION + " by " + EnumChatFormatting.RED + "hannibal2" + EnumChatFormatting.RESET + ", config by " + EnumChatFormatting.DARK_PURPLE + "Moulberry", fr, x + xSize / 2f, y + 15, false, 200, 0xa0a0a0);
GuiRenderUtils.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
);
GuiRenderUtils.drawFloatingRectDark(x + 149, y + 29, xSize - 154, ySize - 34, false);
innerLeft = x + 149 + innerPadding;
innerRight = x + xSize - 5 - innerPadding;
innerBottom = y + ySize - 5 - innerPadding;
Minecraft.getMinecraft().getTextureManager().bindTexture(SEARCH_ICON);
GlStateManager.color(1, 1, 1, 1);
GuiRenderUtils.drawTexturedRect(innerRight - 20, innerTop - (20 + innerPadding) / 2 - 9, 18, 18, GL11.GL_NEAREST);
minimumSearchSize.tick();
boolean shouldShow = !searchField.getText().trim().isEmpty() || searchField.getFocus();
if (shouldShow && minimumSearchSize.getTarget() < 30) {
minimumSearchSize.setTarget(30);
minimumSearchSize.resetTimer();
} else if (!shouldShow && minimumSearchSize.getTarget() > 0) {
minimumSearchSize.setTarget(0);
minimumSearchSize.resetTimer();
}
int rightStuffLen = 20;
if (minimumSearchSize.getValue() > 1) {
int strLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(searchField.getText()) + 10;
if (!shouldShow) strLen = 0;
int len = Math.max(strLen, minimumSearchSize.getValue());
searchField.setSize(len, 18);
searchField.render(innerRight - 25 - len, innerTop - (20 + innerPadding) / 2 - 9);
rightStuffLen += 5 + len;
}
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();
HashMap activeAccordions = new HashMap<>();
for (ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) {
int optionWidth = optionWidthDefault;
if (option.accordionId >= 0) {
if (!activeAccordions.containsKey(option.accordionId)) {
continue;
}
int accordionDepth = activeAccordions.get(option.accordionId);
optionWidth = optionWidthDefault - (2 * innerPadding) * (accordionDepth + 1);
}
GuiOptionEditor editor = option.editor;
if (editor == null) {
continue;
}
if (editor instanceof GuiOptionEditorAccordion) {
GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor;
if (accordion.getToggled()) {
int accordionDepth = 0;
if (option.accordionId >= 0) {
accordionDepth = activeAccordions.get(option.accordionId) + 1;
}
activeAccordions.put(accordion.getAccordionId(), accordionDepth);
}
}
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();
HashMap activeAccordions = new HashMap<>();
for (ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) {
int optionWidth = optionWidthDefault;
if (option.accordionId >= 0) {
if (!activeAccordions.containsKey(option.accordionId)) {
continue;
}
int accordionDepth = activeAccordions.get(option.accordionId);
optionWidth = optionWidthDefault - (2 * innerPadding) * (accordionDepth + 1);
}
GuiOptionEditor editor = option.editor;
if (editor == null) {
continue;
}
if (editor instanceof GuiOptionEditorAccordion) {
GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor;
if (accordion.getToggled()) {
int accordionDepth = 0;
if (option.accordionId >= 0) {
accordionDepth = activeAccordions.get(option.accordionId) + 1;
}
activeAccordions.put(accordion.getAccordionId(), accordionDepth);
}
}
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);
optionsBarStart = optionsScroll.getValue() / (float) (optionY + optionsScroll.getValue());
optionsBarend = optionsBarStart + barSize;
if (optionsBarend > 1) {
optionsBarend = 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 * optionsBarStart),
innerRight - 6,
innerTop + 6 + (int) (dist * optionsBarend),
0xff303030
);
for (int socialIndex = 0; socialIndex < socialsIco.length; socialIndex++) {
Minecraft.getMinecraft().getTextureManager().bindTexture(socialsIco[socialIndex]);
GlStateManager.color(1, 1, 1, 1);
int socialLeft = x + xSize - 23 - 18 * socialIndex;
GuiRenderUtils.drawTexturedRect(socialLeft, y + 7, 16, 16, GL11.GL_LINEAR);
if (mouseX >= 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) {
lastMouseX = mouseX;
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 dist = innerBottom - innerTop - 12;
int optionsBarStartY = innerTop + 6 + (int) (dist * optionsBarStart);
int optionsBarEndY = innerTop + 6 + (int) (dist * optionsBarend);
int optionsBarStartX = innerRight - 12;
int optionsBarEndX = innerRight - 3;
int categoryY = -categoryScroll.getValue();
categoryY += 15 * getCurrentConfigEditing().size();
int catDist = innerBottom - innerTop - 12;
float catBarStart = categoryScroll.getValue() / (float) (categoryY + categoryScroll.getValue());
float categoryBarSize = LerpUtils.clampZeroOne(
(float) (innerBottom - innerTop - 2) / (categoryY + 5 + categoryScroll.getValue()));
float catBarEnd = catBarStart + categoryBarSize;
int categoryBarStartY = innerTop + 6 + (int) (catDist * catBarStart);
int categoryBarEndY = innerTop + 6 + (int) (catDist * catBarEnd);
int categoryBarStartX = x + innerPadding + 7;
int categoryBarEndX = x + innerPadding + 12;
keyboardScrollXCutoff = innerLeft - 10;
if (Mouse.getEventButtonState()) {
if ((mouseY < optionsBarStartY || mouseY > optionsBarEndY) &&
(mouseX >= optionsBarStartX && mouseX <= optionsBarEndX) && mouseY > innerTop + 6 && mouseY < innerBottom - 6) {
optionsScroll.setTimeToReachTarget(200);
optionsScroll.resetTimer();
optionsScroll.setTarget(mouseY - innerTop);
return true;
} else if ((mouseY < categoryBarStartY || mouseY > categoryBarEndY) &&
(mouseX >= categoryBarStartX && mouseX <= categoryBarEndX) && mouseY > innerTop + 6 &&
mouseY < innerBottom - 6) {
categoryScroll.setTimeToReachTarget(200);
categoryScroll.resetTimer();
categoryScroll.setTarget(mouseY - innerTop);
return true;
}
searchField.setFocus(mouseX >= innerRight - 20 && mouseX <= innerRight - 2 &&
mouseY >= innerTop - (20 + innerPadding) / 2 - 9 && mouseY <= innerTop - (20 + innerPadding) / 2 + 9);
if (minimumSearchSize.getValue() > 1) {
int strLen = Minecraft.getMinecraft().fontRendererObj.getStringWidth(searchField.getText()) + 10;
int len = Math.max(strLen, minimumSearchSize.getValue());
if (mouseX >= innerRight - 25 - len && mouseX <= innerRight - 25 &&
mouseY >= innerTop - (20 + innerPadding) / 2 - 9 && mouseY <= innerTop - (20 + innerPadding) / 2 + 9) {
String old = searchField.getText();
searchField.mouseClicked(mouseX, mouseY, Mouse.getEventButton());
if (!searchField.getText().equals(old)) search();
}
}
}
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());
HashMap activeAccordions = new HashMap<>();
for (ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) {
if (option.accordionId >= 0) {
if (!activeAccordions.containsKey(option.accordionId)) {
continue;
}
}
GuiOptionEditor editor = option.editor;
if (editor == null) {
continue;
}
if (editor instanceof GuiOptionEditorAccordion) {
GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor;
if (accordion.getToggled()) {
int accordionDepth = 0;
if (option.accordionId >= 0) {
accordionDepth = activeAccordions.get(option.accordionId) + 1;
}
activeAccordions.put(accordion.getAccordionId(), accordionDepth);
}
}
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 < socialsLink.length; socialIndex++) {
int socialLeft = x + xSize - 23 - 18 * socialIndex;
if (mouseX >= 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());
HashMap activeAccordions = new HashMap<>();
for (ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) {
int optionWidth = optionWidthDefault;
if (option.accordionId >= 0) {
if (!activeAccordions.containsKey(option.accordionId)) {
continue;
}
int accordionDepth = activeAccordions.get(option.accordionId);
optionWidth = optionWidthDefault - (2 * innerPadding) * (accordionDepth + 1);
}
GuiOptionEditor editor = option.editor;
if (editor == null) {
continue;
}
if (editor instanceof GuiOptionEditorAccordion) {
GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor;
if (accordion.getToggled()) {
int accordionDepth = 0;
if (option.accordionId >= 0) {
accordionDepth = activeAccordions.get(option.accordionId) + 1;
}
activeAccordions.put(accordion.getAccordionId(), accordionDepth);
}
}
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());
HashMap activeAccordions = new HashMap<>();
for (ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) {
int optionWidth = optionWidthDefault;
if (option.accordionId >= 0) {
if (!activeAccordions.containsKey(option.accordionId)) {
continue;
}
int accordionDepth = activeAccordions.get(option.accordionId);
optionWidth = optionWidthDefault - (2 * innerPadding) * (accordionDepth + 1);
}
GuiOptionEditor editor = option.editor;
if (editor == null) {
continue;
}
if (editor instanceof GuiOptionEditorAccordion) {
GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor;
if (accordion.getToggled()) {
int accordionDepth = 0;
if (option.accordionId >= 0) {
accordionDepth = activeAccordions.get(option.accordionId) + 1;
}
activeAccordions.put(accordion.getAccordionId(), accordionDepth);
}
}
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 (Keyboard.getEventKeyState()) {
String old = searchField.getText();
searchField.keyTyped(Keyboard.getEventCharacter(), Keyboard.getEventKey());
searchField.setText(Minecraft.getMinecraft().fontRendererObj.trimStringToWidth(
searchField.getText(),
innerWidth / 2 - 20
));
if (!searchField.getText().equals(old)) search();
}
if (getSelectedCategory() != null && getCurrentConfigEditing() != null &&
getCurrentConfigEditing().containsKey(getSelectedCategory())) {
ConfigProcessor.ProcessedCategory cat = getCurrentConfigEditing().get(getSelectedCategory());
HashMap activeAccordions = new HashMap<>();
for (ConfigProcessor.ProcessedOption option : getOptionsInCategory(cat).values()) {
if (option.accordionId >= 0) {
if (!activeAccordions.containsKey(option.accordionId)) {
continue;
}
}
GuiOptionEditor editor = option.editor;
if (editor == null) {
continue;
}
if (editor instanceof GuiOptionEditorAccordion) {
GuiOptionEditorAccordion accordion = (GuiOptionEditorAccordion) editor;
if (accordion.getToggled()) {
int accordionDepth = 0;
if (option.accordionId >= 0) {
accordionDepth = activeAccordions.get(option.accordionId) + 1;
}
activeAccordions.put(accordion.getAccordionId(), accordionDepth);
}
}
if (editor.keyboardInput()) {
return true;
}
}
}
return true;
}
private void handleKeyboardPresses() {
LerpingInteger target = lastMouseX < keyboardScrollXCutoff ? categoryScroll : optionsScroll;
if (Keyboard.isKeyDown(Keyboard.KEY_DOWN)) {
target.setTimeToReachTarget(50);
target.resetTimer();
target.setTarget(target.getTarget() + 5);
} else if (Keyboard.isKeyDown(Keyboard.KEY_UP)) {
target.setTimeToReachTarget(50);
target.resetTimer();
if (target.getTarget() >= 0) {
target.setTarget(target.getTarget() - 5);
}
}
if (Keyboard.isKeyDown(Keyboard.KEY_ESCAPE)) {
SkyHanniMod.configManager.saveConfig();
}
}
}