aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/cc/polyfrost/oneconfig/gui
diff options
context:
space:
mode:
authorDeDiamondPro <67508414+DeDiamondPro@users.noreply.github.com>2022-05-03 18:25:32 +0200
committerDeDiamondPro <67508414+DeDiamondPro@users.noreply.github.com>2022-05-03 18:25:32 +0200
commita0ff501947a84b268e099524a06b56a6b900dad2 (patch)
treedb27ca1b28dbc7e57b8c99f54c80732d3042e856 /src/main/java/cc/polyfrost/oneconfig/gui
parentb798930b21b89b81be05a31281f768667a6dd7f3 (diff)
downloadOneConfig-a0ff501947a84b268e099524a06b56a6b900dad2.tar.gz
OneConfig-a0ff501947a84b268e099524a06b56a6b900dad2.tar.bz2
OneConfig-a0ff501947a84b268e099524a06b56a6b900dad2.zip
move to cc.polyfrost
Diffstat (limited to 'src/main/java/cc/polyfrost/oneconfig/gui')
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/HudGui.java326
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/OneConfigGui.java231
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/SideBar.java67
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/BasicButton.java157
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/BasicElement.java107
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/ColorSelector.java250
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/ModCard.java146
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/SearchField.java14
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/TextInputField.java418
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigCheckbox.java61
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigColorElement.java115
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigDropdown.java167
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigDualOption.java53
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigPageButton.java57
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigSlider.java184
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigSwitch.java54
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigTextBox.java61
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigUniSelector.java78
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/pages/HomePage.java28
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/pages/ModConfigPage.java152
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/pages/ModsPage.java76
-rw-r--r--src/main/java/cc/polyfrost/oneconfig/gui/pages/Page.java31
22 files changed, 2833 insertions, 0 deletions
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/HudGui.java b/src/main/java/cc/polyfrost/oneconfig/gui/HudGui.java
new file mode 100644
index 0000000..c3437fa
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/HudGui.java
@@ -0,0 +1,326 @@
+package cc.polyfrost.oneconfig.gui;
+
+import cc.polyfrost.oneconfig.hud.HudCore;
+import cc.polyfrost.oneconfig.hud.interfaces.BasicHud;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.gui.GuiScreen;
+import org.lwjgl.input.Keyboard;
+
+import java.awt.*;
+import java.io.IOException;
+import java.util.ArrayList;
+
+public class HudGui extends GuiScreen {
+ private BasicHud editingHud;
+ private boolean isDragging;
+ private boolean isScaling;
+ private int xOffset;
+ private int yOffset;
+
+ @Override
+ public void initGui() {
+ HudCore.editing = true;
+ Keyboard.enableRepeatEvents(true);
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ Gui.drawRect(0, 0, this.width, this.height, new Color(80, 80, 80, 50).getRGB());
+
+ if (isDragging) {
+ setPosition(mouseX - xOffset, mouseY - yOffset, true);
+ }
+
+ for (BasicHud hud : HudCore.huds) {
+ processHud(hud, mouseX);
+ }
+ }
+
+ private void processHud(BasicHud hud, int mouseX) {
+ if (hud == editingHud && isScaling) {
+ float xFloat = hud.getXScaled(this.width);
+ float yFloat = hud.getYScaled(this.height);
+ float pos = getXSnapping(mouseX, true);
+ float newWidth = pos - xFloat;
+ float newScale = newWidth / ((hud.getWidth(hud.scale) + hud.paddingX * hud.scale) / hud.scale);
+ if (newScale > 20)
+ newScale = 20;
+ else if (newScale < 0.3)
+ newScale = 0.3f;
+ hud.scale = newScale;
+
+ if (xFloat / this.width > 0.5)
+ editingHud.xUnscaled = (xFloat + (hud.getWidth(hud.scale) + hud.paddingX * hud.scale)) / (double) this.width;
+ if (yFloat / this.height > 0.5)
+ editingHud.yUnscaled = (yFloat + (hud.getHeight(hud.scale) + hud.paddingY * hud.scale)) / (double) this.height;
+ }
+
+ int width = (int) (hud.getWidth(hud.scale) + hud.paddingX * hud.scale);
+ int height = (int) (hud.getHeight(hud.scale) + hud.paddingY * hud.scale);
+ int x = (int) hud.getXScaled(this.width);
+ int y = (int) hud.getYScaled(this.height);
+
+ if (hud.parent == null)
+ hud.drawExampleAll(x, y, hud.scale, true);
+ int color = new Color(215, 224, 235).getRGB();
+ if (editingHud == hud) {
+ color = new Color(43, 159, 235).getRGB();
+ if (isDragging)
+ Gui.drawRect(x, y, x + width, y + height, new Color(108, 176, 255, 60).getRGB());
+ }
+ int finalColor = color;
+ RenderManager.setupAndDraw(true, (vg) -> {
+ RenderManager.drawLine(vg, x - 2 / 4f, y, x + width + 2 / 4f, y, 1, finalColor);
+ RenderManager.drawLine(vg, x, y, x, y + height, 1, finalColor);
+ RenderManager.drawLine(vg, x + width, y, x + width, y + height, 1, finalColor);
+ RenderManager.drawLine(vg, x - 2 / 4f, y + height, x + width + 2 / 4f, y + height, 1, finalColor);
+ });
+
+ if (hud == editingHud && !isDragging) {
+ RenderManager.setupAndDraw(true, (vg) -> {
+ RenderManager.drawCircle(vg, x + width, y + height, 3, new Color(43, 159, 235).getRGB());
+ });
+ }
+
+ if (hud.childBottom != null) processHud(hud.childBottom, mouseX);
+ if (hud.childRight != null) processHud(hud.childRight, mouseX);
+ }
+
+ private void setPosition(float newX, float newY, boolean snap) {
+ float width = editingHud.getWidth(editingHud.scale) + editingHud.paddingX * editingHud.scale;
+ float height = editingHud.getHeight(editingHud.scale) + editingHud.paddingY * editingHud.scale;
+
+ if (editingHud.childRight != null) {
+ HudCore.huds.add(editingHud.childRight);
+ editingHud.childRight.parent = null;
+ editingHud.childRight = null;
+ }
+ if (editingHud.childBottom != null) {
+ HudCore.huds.add(editingHud.childBottom);
+ editingHud.childBottom.parent = null;
+ editingHud.childBottom = null;
+ }
+ if (editingHud.parent != null) {
+ HudCore.huds.add(editingHud);
+ if (editingHud.parent.childBottom == editingHud)
+ editingHud.parent.childBottom = null;
+ else if (editingHud.parent.childRight == editingHud)
+ editingHud.parent.childRight = null;
+ editingHud.parent = null;
+ }
+
+ if (newX < 0)
+ newX = 0;
+ else if (newX + width > this.width)
+ newX = this.width - width;
+ if (newY < 0)
+ newY = 0;
+ else if (newY + height > this.height)
+ newY = this.height - height;
+
+ if (snap) {
+ float snapX = getXSnapping(newX, false);
+ float snapY = getYSnapping(newY);
+ if (snapX != newX || snapY != newY) {
+ newX = snapX;
+ newY = snapY;
+ for (BasicHud hud : HudCore.huds) {
+ if (findParent(hud, snapX, snapY))
+ break;
+ }
+ }
+ }
+
+ if (newX / this.width <= 0.5)
+ editingHud.xUnscaled = newX / (double) this.width;
+ else
+ editingHud.xUnscaled = (newX + width) / (double) this.width;
+ if (newY / this.height <= 0.5)
+ editingHud.yUnscaled = newY / (double) this.height;
+ else
+ editingHud.yUnscaled = (newY + height) / (double) this.height;
+ }
+
+ private boolean findParent(BasicHud hud, float snapX, float snapY) {
+ int hudWidth = (int) (hud.getWidth(hud.scale) + hud.paddingX * hud.scale);
+ int hudX = (int) hud.getXScaled(this.width);
+ int hudHeight = (int) (hud.getHeight(hud.scale) + hud.paddingY * hud.scale);
+ int hudY = (int) hud.getYScaled(this.height);
+ if (hudX + hudWidth == snapX && hudY == snapY && hud.childRight == null) {
+ editingHud.parent = hud;
+ hud.childRight = editingHud;
+ HudCore.huds.remove(editingHud);
+ return true;
+ } else if (hudX == snapX && hudY + hudHeight == snapY && hud.childBottom == null) {
+ editingHud.parent = hud;
+ hud.childBottom = editingHud;
+ HudCore.huds.remove(editingHud);
+ return true;
+ }
+ return hud.childRight != null && findParent(hud.childRight, snapX, snapY) || hud.childBottom != null && findParent(hud.childBottom, snapX, snapY);
+ }
+
+ private float getXSnapping(float pos, boolean rightOnly) {
+ float width = editingHud.getWidth(editingHud.scale) + editingHud.paddingX * editingHud.scale;
+ ArrayList<Float> verticalLines = new ArrayList<>();
+ for (BasicHud hud : HudCore.huds) {
+ verticalLines.addAll(getXSnappingHud(hud));
+ }
+ getSpaceSnapping(verticalLines);
+ verticalLines.add(this.width / 2f);
+ float smallestDiff = -1;
+ float smallestLine = 0;
+ float smallestOffset = 0;
+ for (float lineX : verticalLines) {
+ for (float offset = 0; offset <= (rightOnly ? 0 : width); offset += width / 2f) {
+ if (Math.abs(lineX - pos - offset) < 5 && (Math.abs(lineX - pos - offset) < smallestDiff || smallestDiff == -1)) {
+ smallestDiff = Math.abs(lineX - pos);
+ smallestLine = lineX;
+ smallestOffset = offset;
+ }
+ }
+ }
+ if (smallestDiff != -1) {
+ RenderManager.drawDottedLine(smallestLine, 0, smallestLine, this.height, 2, 12, new Color(255, 255, 255).getRGB());
+ return smallestLine - smallestOffset;
+ }
+ return pos;
+ }
+
+ private ArrayList<Float> getXSnappingHud(BasicHud hud) {
+ ArrayList<Float> verticalLines = new ArrayList<>();
+ if (hud == editingHud) return verticalLines;
+ if (hud.childRight != null) verticalLines.addAll(getXSnappingHud(hud.childRight));
+ int hudWidth = (int) (hud.getWidth(hud.scale) + hud.paddingX * hud.scale);
+ int hudX = (int) hud.getXScaled(this.width);
+ verticalLines.add((float) hudX);
+ verticalLines.add((float) (hudX + hudWidth));
+ return verticalLines;
+ }
+
+ private float getYSnapping(float pos) {
+ float height = editingHud.getHeight(editingHud.scale) + editingHud.paddingY * editingHud.scale;
+ ArrayList<Float> horizontalLines = new ArrayList<>();
+ for (BasicHud hud : HudCore.huds) {
+ horizontalLines.addAll(getYSnappingHud(hud));
+ }
+ getSpaceSnapping(horizontalLines);
+ horizontalLines.add(this.height / 2f);
+ float smallestDiff = -1;
+ float smallestLine = 0;
+ float smallestOffset = 0;
+ for (float lineY : horizontalLines) {
+ for (float offset = 0; offset <= height; offset += height / 2f) {
+ if (Math.abs(lineY - pos - offset) < 5 && (Math.abs(lineY - pos - offset) < smallestDiff || smallestDiff == -1)) {
+ smallestDiff = Math.abs(lineY - pos);
+ smallestLine = lineY;
+ smallestOffset = offset;
+ }
+ }
+ }
+ if (smallestDiff != -1) {
+ RenderManager.drawDottedLine(0, smallestLine, this.width, smallestLine, 2, 12, new Color(255, 255, 255).getRGB());
+ return smallestLine - smallestOffset;
+ }
+ return pos;
+ }
+
+ private ArrayList<Float> getYSnappingHud(BasicHud hud) {
+ ArrayList<Float> horizontalLines = new ArrayList<>();
+ if (hud == editingHud) return horizontalLines;
+ if (hud.childBottom != null) horizontalLines.addAll(getYSnappingHud(hud.childBottom));
+ int hudHeight = (int) (hud.getHeight(hud.scale) + hud.paddingY * hud.scale);
+ int hudY = (int) hud.getYScaled(this.height);
+ horizontalLines.add((float) hudY);
+ horizontalLines.add((float) (hudY + hudHeight));
+ return horizontalLines;
+ }
+
+ private void getSpaceSnapping(ArrayList<Float> lines) {
+ ArrayList<Float> newLines = new ArrayList<>();
+ for (int i = 0; i < lines.size(); i++) {
+ for (int l = i + 1; l < lines.size(); l++) {
+ newLines.add(Math.max(lines.get(i), lines.get(l)) + Math.abs(lines.get(i) - lines.get(l)));
+ newLines.add(Math.min(lines.get(i), lines.get(l)) - Math.abs(lines.get(i) - lines.get(l)));
+ }
+ }
+ lines.addAll(newLines);
+ }
+
+ @Override
+ protected void mouseClicked(int mouseX, int mouseY, int mouseButton) {
+ if (mouseButton == 0) {
+ if (editingHud != null) {
+ int width = (int) (editingHud.getWidth(editingHud.scale) + editingHud.paddingX * editingHud.scale);
+ int height = (int) (editingHud.getHeight(editingHud.scale) + editingHud.paddingY * editingHud.scale);
+ float x = editingHud.getXScaled(this.width);
+ float y = editingHud.getYScaled(this.height);
+ if (mouseX >= x + width - 3 && mouseX <= x + width + 3 && mouseY >= y + height - 3 && mouseY <= y + height + 3) {
+ isScaling = true;
+ return;
+ }
+ }
+ editingHud = null;
+ for (BasicHud hud : HudCore.huds) {
+ if (mouseClickedHud(hud, mouseX, mouseY))
+ break;
+ }
+ }
+ }
+
+ private boolean mouseClickedHud(BasicHud hud, int mouseX, int mouseY) {
+ int width = (int) (hud.getWidth(hud.scale) + hud.paddingX * hud.scale);
+ int height = (int) (hud.getHeight(hud.scale) + hud.paddingY * hud.scale);
+ float x = hud.getXScaled(this.width);
+ float y = hud.getYScaled(this.height);
+ if (mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height) {
+ editingHud = hud;
+ xOffset = (int) (mouseX - x);
+ yOffset = (int) (mouseY - y);
+ isDragging = true;
+ return true;
+ }
+ return hud.childBottom != null && mouseClickedHud(hud.childBottom, mouseX, mouseY) || hud.childRight != null && mouseClickedHud(hud.childRight, mouseX, mouseY);
+ }
+
+ @Override
+ protected void mouseReleased(int mouseX, int mouseY, int state) {
+ isDragging = false;
+ isScaling = false;
+ }
+
+ @Override
+ protected void keyTyped(char typedChar, int keyCode) throws IOException {
+ if (editingHud != null) {
+ float x = editingHud.getXScaled(this.width);
+ float y = editingHud.getYScaled(this.height);
+ switch (keyCode) {
+ case Keyboard.KEY_UP:
+ setPosition(x, y - 1, false);
+ break;
+ case Keyboard.KEY_DOWN:
+ setPosition(x, y + 1, false);
+ break;
+ case Keyboard.KEY_LEFT:
+ setPosition(x - 1, y, false);
+ break;
+ case Keyboard.KEY_RIGHT:
+ setPosition(x + 1, y, false);
+ break;
+ }
+ }
+ super.keyTyped(typedChar, keyCode);
+ }
+
+ @Override
+ public void onGuiClosed() {
+ HudCore.editing = false;
+ Keyboard.enableRepeatEvents(false);
+ }
+
+ @Override
+ public boolean doesGuiPauseGame() {
+ return false;
+ }
+} \ No newline at end of file
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/OneConfigGui.java b/src/main/java/cc/polyfrost/oneconfig/gui/OneConfigGui.java
new file mode 100644
index 0000000..72cd8c0
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/OneConfigGui.java
@@ -0,0 +1,231 @@
+package cc.polyfrost.oneconfig.gui;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.gui.elements.BasicElement;
+import cc.polyfrost.oneconfig.gui.elements.ColorSelector;
+import cc.polyfrost.oneconfig.gui.elements.TextInputField;
+import cc.polyfrost.oneconfig.gui.pages.HomePage;
+import cc.polyfrost.oneconfig.gui.pages.Page;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.Scissor;
+import cc.polyfrost.oneconfig.lwjgl.ScissorManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import cc.polyfrost.oneconfig.utils.MathUtils;
+import net.minecraft.client.gui.GuiScreen;
+import org.jetbrains.annotations.NotNull;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.nanovg.NanoVG;
+
+import java.awt.*;
+import java.util.ArrayList;
+
+public class OneConfigGui extends GuiScreen {
+ public static OneConfigGui INSTANCE;
+ public final int x = 320;
+ public final int y = 140;
+ private final SideBar sideBar = new SideBar();
+ protected Page currentPage;
+ protected Page prevPage;
+ private float pageProgress = -224f;
+ private final TextInputField textInputField = new TextInputField(248, 40, "Search all of OneConfig...", false, false);
+ private final ArrayList<Page> previousPages = new ArrayList<>();
+ private final ArrayList<Page> nextPages = new ArrayList<>();
+ private final BasicElement backArrow = new BasicElement(40, 40, -1, false);
+ private final BasicElement forwardArrow = new BasicElement(40, 40, -1, false);
+ private final ArrayList<Page> parents = new ArrayList<>();
+ private ColorSelector currentColorSelector;
+ public boolean mouseDown;
+
+ public OneConfigGui() {
+ INSTANCE = this;
+ }
+
+ public OneConfigGui(Page page) {
+ INSTANCE = this;
+ currentPage = page;
+ }
+
+ @Override
+ public void drawScreen(int mouseX, int mouseY, float partialTicks) {
+ super.drawScreen(mouseX, mouseY, partialTicks);
+ long start = System.nanoTime();
+ RenderManager.setupAndDraw((vg) -> {
+ if (currentPage == null) {
+ currentPage = new HomePage();
+ parents.add(currentPage);
+ }
+ //nvgScale(vg, 0.5f, 0.5f);
+ if (OneConfigConfig.ROUNDED_CORNERS) {
+ RenderManager.drawRoundedRect(vg, 544, 140, 1056, 800, OneConfigConfig.GRAY_800, OneConfigConfig.CORNER_RADIUS_WIN);
+ RenderManager.drawRoundedRect(vg, 320, 140, 244, 800, OneConfigConfig.GRAY_900_80, OneConfigConfig.CORNER_RADIUS_WIN);
+ RenderManager.drawRect(vg, 544, 140, 20, 800, OneConfigConfig.GRAY_800);
+ //RenderManager.drawDropShadow(vg, 544, 140, 1056, 800, 20f, 32f, OneConfigConfig.GRAY_800);
+ }
+
+ RenderManager.drawLine(vg, 544, 212, 1600, 212, 1, OneConfigConfig.GRAY_700);
+ RenderManager.drawLine(vg, 544, 140, 544, 940, 1, OneConfigConfig.GRAY_700);
+
+ RenderManager.drawImage(vg, Images.LOGO, x + 19, y + 19, 42, 42);
+ RenderManager.drawString(vg, "OneConfig", x + 69, y + 32, OneConfigConfig.WHITE, 18f, Fonts.INTER_BOLD); // added half line height to center text
+ RenderManager.drawString(vg, "By Polyfrost", x + 69, y + 51, OneConfigConfig.WHITE, 12f, Fonts.INTER_REGULAR);
+ textInputField.draw(vg, x + 1020, y + 16);
+ sideBar.draw(vg, x, y);
+ backArrow.draw(vg, x + 240, y + 16);
+ forwardArrow.draw(vg, x + 280, y + 16);
+
+ if (previousPages.size() == 0) {
+ backArrow.disable(true);
+ NanoVG.nvgGlobalAlpha(vg, 0.5f);
+ } else {
+ backArrow.disable(false);
+ if (!backArrow.isHovered() || Mouse.isButtonDown(0)) NanoVG.nvgGlobalAlpha(vg, 0.8f);
+ }
+ NanoVG.nvgTranslate(vg, x + 271, y + 47);
+ NanoVG.nvgRotate(vg, (float) Math.toRadians(180));
+ RenderManager.drawImage(vg, Images.CIRCLE_ARROW, 0, 0, 22, 22);
+ NanoVG.nvgResetTransform(vg);
+ NanoVG.nvgGlobalAlpha(vg, 1f);
+ if (nextPages.size() == 0) {
+ forwardArrow.disable(true);
+ NanoVG.nvgGlobalAlpha(vg, 0.5f);
+ } else {
+ forwardArrow.disable(false);
+ if (!forwardArrow.isHovered() || Mouse.isButtonDown(0)) NanoVG.nvgGlobalAlpha(vg, 0.8f);
+ }
+ RenderManager.drawImage(vg, Images.CIRCLE_ARROW, x + 289, y + 25, 22, 22);
+ NanoVG.nvgGlobalAlpha(vg, 1f);
+
+ if (backArrow.isClicked() && previousPages.size() > 0) {
+ try {
+ nextPages.add(0, currentPage);
+ openPage(previousPages.get(0), false);
+ previousPages.remove(0);
+ } catch (Exception ignored) {
+ }
+ } else if (forwardArrow.isClicked() && nextPages.size() > 0) {
+ try {
+ previousPages.add(0, currentPage);
+ openPage(nextPages.get(0), false);
+ nextPages.remove(0);
+ } catch (Exception ignored) {
+ }
+ }
+
+ Scissor scissor = ScissorManager.scissor(vg, x + 224, y + 72, 1056, 728);
+ if (prevPage != null) {
+ pageProgress = MathUtils.easeInOutCirc(50, pageProgress, 832 - pageProgress, 220);
+ prevPage.draw(vg, (int) (x - pageProgress), y + 72);
+ RenderManager.drawLine(vg, (int) (x - pageProgress + 1055), y + 72, (int) (x - pageProgress + 1057), y + 800, 2, OneConfigConfig.GRAY_700); // TODO might remove this
+ currentPage.draw(vg, (int) (x - pageProgress + 1056), y + 72);
+ if (pageProgress > 830f) { // this number is the 'snap' point of the page
+ prevPage = null;
+ pageProgress = -224f;
+ }
+ } else {
+ currentPage.draw(vg, (int) (x - pageProgress), y + 72);
+ }
+ ScissorManager.resetScissor(vg, scissor);
+ if (currentColorSelector != null) {
+ currentColorSelector.draw(vg);
+ }
+
+ float breadcrumbX = x + 336;
+ for (int i = 0; i < parents.size(); i++) {
+ String title = parents.get(i).getTitle();
+ float width = RenderManager.getTextWidth(vg, title, 24f, Fonts.INTER_SEMIBOLD);
+ boolean hovered = InputUtils.isAreaHovered((int) breadcrumbX, y + 24, (int) width, 36);
+ int color = OneConfigConfig.WHITE_60;
+ if (i == parents.size() - 1) color = OneConfigConfig.WHITE_95;
+ else if (hovered && !Mouse.isButtonDown(0)) color = OneConfigConfig.WHITE_80;
+ RenderManager.drawString(vg, title, breadcrumbX, y + 38, color, 24f, Fonts.INTER_SEMIBOLD);
+ if (i != 0)
+ RenderManager.drawImage(vg, Images.CHEVRON_ARROW, breadcrumbX - 22, y + 26, 13, 22, color);
+ if (hovered && i != parents.size() - 1)
+ RenderManager.drawLine(vg, breadcrumbX, y + 48, breadcrumbX + width, y + 48, 2, color);
+ if (hovered && InputUtils.isClicked()) openPage(parents.get(i));
+ breadcrumbX += width + 32;
+ }
+
+ long end = System.nanoTime() - start;
+ String s = (" draw: " + end / 1000000f + "ms");
+ RenderManager.drawString(vg, s, x + 1170, y + 790, OneConfigConfig.GRAY_300, 10f, Fonts.INTER_MEDIUM);
+ });
+ mouseDown = Mouse.isButtonDown(0);
+ }
+
+ protected void keyTyped(char key, int keyCode) {
+ Keyboard.enableRepeatEvents(true);
+ try {
+ super.keyTyped(key, keyCode);
+ textInputField.keyTyped(key, keyCode);
+ currentPage.keyTyped(key, keyCode);
+ } catch (Exception e) {
+ System.out.println("this should literally never happen");
+ }
+ }
+
+ public void openPage(@NotNull Page page) {
+ openPage(page, true);
+ }
+
+ public void openPage(@NotNull Page page, boolean addToPrevious) {
+ if (page == currentPage) return;
+ currentPage.finishUpAndClose();
+ if (!page.isBase()) {
+ boolean alreadyInParents = false;
+ for (int i = 0; i < parents.size(); i++) {
+ Page parent = parents.get(i);
+ if (parent == page) {
+ alreadyInParents = true;
+ parents.subList(i + 1, parents.size()).clear();
+ break;
+ }
+ }
+ if (!alreadyInParents) parents.add(page);
+ } else {
+ parents.clear();
+ parents.add(page);
+ }
+ if (addToPrevious) {
+ previousPages.add(0, currentPage);
+ nextPages.clear();
+ }
+ if (prevPage == null) {
+ prevPage = currentPage;
+ }
+ currentPage = page;
+ }
+
+ /**
+ * initialize a new ColorSelector and add it to the draw script. This method is used to make sure it is always rendered on top.
+ *
+ * @implNote Correct usage: <code>OneConfigGui.INSTANCE.initColorSelector(new ColorSelector(color, InputUtils.mouseX(), InputUtils.mouseY()));</code>
+ */
+ public void initColorSelector(ColorSelector colorSelector) {
+ currentColorSelector = colorSelector;
+ }
+
+ /**
+ * Close the current color selector and return the color it had when it closed.
+ */
+ public Color closeColorSelector() {
+ Color color = currentColorSelector.getColor();
+ currentColorSelector = null;
+ return color;
+ }
+
+
+ @Override
+ public boolean doesGuiPauseGame() {
+ return false;
+ }
+
+ @Override
+ public void onGuiClosed() {
+ currentPage.finishUpAndClose();
+ INSTANCE = null;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/SideBar.java b/src/main/java/cc/polyfrost/oneconfig/gui/SideBar.java
new file mode 100644
index 0000000..73f46f7
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/SideBar.java
@@ -0,0 +1,67 @@
+package cc.polyfrost.oneconfig.gui;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.gui.elements.BasicButton;
+import cc.polyfrost.oneconfig.gui.pages.HomePage;
+import cc.polyfrost.oneconfig.gui.pages.ModsPage;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+import cc.polyfrost.oneconfig.utils.MathUtils;
+import net.minecraft.client.Minecraft;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SideBar {
+ private final List<BasicButton> btnList = new ArrayList<>();
+
+ private float targetY = 0, currentY = 0;
+
+ public SideBar() {
+ btnList.add(new BasicButton(192, 36, "Dashboard", Images.DASHBOARD, null, -3, BasicButton.ALIGNMENT_LEFT, new HomePage()));
+ btnList.add(new BasicButton(192, 36, "Global Search", Images.SEARCH, null, -3, BasicButton.ALIGNMENT_LEFT));
+ btnList.add(new BasicButton(192, 36, "Mods", Images.MODS, null, -3, BasicButton.ALIGNMENT_LEFT, new ModsPage()));
+ btnList.add(new BasicButton(192, 36, "Performance", Images.PERFORMANCE, null, -3, BasicButton.ALIGNMENT_LEFT));
+ btnList.add(new BasicButton(192, 36, "Profiles", Images.PROFILES, null, -3, BasicButton.ALIGNMENT_LEFT));
+ btnList.add(new BasicButton(192, 36, "Updates", Images.UPDATES, null, -3, BasicButton.ALIGNMENT_LEFT));
+ btnList.add(new BasicButton(192, 36, "Theme", Images.THEMES, null, -3, BasicButton.ALIGNMENT_LEFT));
+ btnList.add(new BasicButton(192, 36, "Screenshots", Images.SCREENSHOT, null, -3, BasicButton.ALIGNMENT_LEFT));
+ btnList.add(new BasicButton(192, 36, "HUD Settings", Images.HUD_SETTINGS, null, -3, BasicButton.ALIGNMENT_LEFT));
+ btnList.add(new BasicButton(192, 36, "Preferences", Images.PREFERENCES, null, -3, BasicButton.ALIGNMENT_LEFT));
+ btnList.add(new BasicButton(192, 36, "Close", Images.CLOSE, null, -1, BasicButton.ALIGNMENT_LEFT, () -> Minecraft.getMinecraft().displayGuiScreen(null)));
+ btnList.add(new BasicButton(192, 36, "Minimize", Images.MINIMIZE, null, -1, BasicButton.ALIGNMENT_LEFT));
+ btnList.add(new BasicButton(192, 36, "Edit HUD", Images.HUD, null, 0, BasicButton.ALIGNMENT_LEFT, () -> Minecraft.getMinecraft().displayGuiScreen(new HudGui())));
+ }
+
+ public void draw(long vg, int x, int y) {
+ //percentMove = 36f;
+
+ currentY = MathUtils.easeInOutCirc(50, currentY, targetY - currentY, 120);
+ RenderManager.drawRoundedRect(vg, x + 16, currentY, 192, 36, OneConfigConfig.BLUE_600, OneConfigConfig.CORNER_RADIUS);
+ int i = 0;
+ if (targetY == 0) {
+ targetY = y + 96;
+ currentY = targetY;
+ }
+ for (BasicButton btn : btnList) {
+ btn.draw(vg, x + 16, y + 96 + i);
+ i += 44;
+ if (i == 88) { // +88
+ RenderManager.drawString(vg, "MOD CONFIG", x + 16, y + 200, OneConfigConfig.WHITE_90, 12f, Fonts.INTER_SEMIBOLD);
+ i = 122;
+ }
+ if (i == 298) {
+ RenderManager.drawString(vg, "PERSONALIZATION", x + 16, y + 420, OneConfigConfig.WHITE_90, 12f, Fonts.INTER_SEMIBOLD);
+ i = 342;
+ }
+ if (i == 518) {
+ i = 562;
+ }
+
+ if (btn.isClicked() && btn.getPage() != null) {
+ if (i < 520) targetY = btn.y;
+ }
+ }
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/BasicButton.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/BasicButton.java
new file mode 100644
index 0000000..faf0b07
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/BasicButton.java
@@ -0,0 +1,157 @@
+package cc.polyfrost.oneconfig.gui.elements;
+
+import cc.polyfrost.oneconfig.gui.OneConfigGui;
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.gui.pages.Page;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+import cc.polyfrost.oneconfig.utils.ColorUtils;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class BasicButton extends BasicElement {
+
+ protected String text;
+ protected Images fileNameLeftIco, fileNameRightIco;
+ private final int thisAlignment;
+ private final float fontSize;
+ private final int colorPalette;
+ public int x, y;
+ public static final int ALIGNMENT_LEFT = 0;
+ public static final int ALIGNMENT_CENTER = 1;
+ private boolean toggleable;
+ private Page page;
+ private Runnable runnable;
+
+ /**
+ * Create a new basic button. Used mostly on the homepage and the sidebar. Note: The button will not be drawn until you call {@link #draw(long, int, int)}.
+ * The button's content is centered on its total length, so the text is not always in the middle.
+ *
+ * @param text Text to display on the button. Has to be there.
+ * @param fileNameLeftIco file path of the icon to display on the left. Can be null if you don't want to display an icon on the left.
+ * @param fileNameRightIco file path of the icon to display on the right. Can be null if you don't want to display an icon on the right.
+ * @param colorPalette color palette to use. see {@link ColorUtils} for more info. Can support color palette of -2, which is larger font and icons. Also supports -3, which is just the text changing color.
+ * @param alignment alignment of the button. ALIGNMENT_LEFT or ALIGNMENT_CENTER.
+ */
+ public BasicButton(int width, int height, @NotNull String text, @Nullable Images fileNameLeftIco, @Nullable Images fileNameRightIco, int colorPalette, int alignment) {
+ super(width, height, colorPalette, true);
+ this.text = text;
+ if (fileNameLeftIco != null) this.fileNameLeftIco = fileNameLeftIco;
+ if (fileNameRightIco != null) this.fileNameRightIco = fileNameRightIco;
+ this.thisAlignment = alignment;
+ if (colorPalette == -2) {
+ fontSize = 24f;
+ this.colorPalette = -1;
+ } else {
+ fontSize = 14f;
+ this.colorPalette = colorPalette;
+ }
+ }
+
+ public BasicButton(int width, int height, @NotNull String text, @Nullable Images fileNameLeftIco, @Nullable Images fileNameRightIco, int colorPalette, int alignment, Page page) {
+ this(width, height, text, fileNameLeftIco, fileNameRightIco, colorPalette, alignment);
+ this.page = page;
+ }
+
+ public BasicButton(int width, int height, @NotNull String text, @Nullable Images fileNameLeftIco, @Nullable Images fileNameRightIco, int colorPalette, int alignment, boolean toggleable) {
+ this(width, height, text, fileNameLeftIco, fileNameRightIco, colorPalette, alignment);
+ this.toggleable = toggleable;
+ }
+
+ public BasicButton(int width, int height, @NotNull String text, @Nullable Images fileNameLeftIco, @Nullable Images fileNameRightIco, int colorPalette, int alignment, Runnable runnable) {
+ this(width, height, text, fileNameLeftIco, fileNameRightIco, colorPalette, alignment);
+ this.runnable = runnable;
+ }
+
+ public BasicButton(int width, int height, @NotNull String text, @Nullable Images fileNameLeftIco, @Nullable Images fileNameRightIco, int colorPalette, int alignment, boolean toggleable, Runnable runnable) {
+ this(width, height, text, fileNameLeftIco, fileNameRightIco, colorPalette, alignment, runnable);
+ this.toggleable = toggleable;
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ this.x = x;
+ this.y = y;
+ int textColor = -1;
+ RenderManager.drawRectangle(vg, x, y, this.width, this.height, this.currentColor);
+ float contentWidth = RenderManager.getTextWidth(vg, text, fontSize, Fonts.INTER_MEDIUM);
+ if (fileNameLeftIco != null) {
+ contentWidth += 28;
+ }
+ if (fileNameRightIco != null) {
+ contentWidth += 28;
+ }
+
+ if (this.colorPalette == -3) {
+ textColor = OneConfigConfig.WHITE_80;
+ if (hovered) textColor = OneConfigConfig.WHITE;
+ if (clicked) textColor = OneConfigConfig.WHITE_80;
+ if (page == null) textColor = OneConfigConfig.WHITE_50;
+ }
+
+ if (thisAlignment == ALIGNMENT_CENTER) {
+ int middle = x + this.width / 2;
+ RenderManager.drawString(vg, text, middle - contentWidth / 2 + (fileNameLeftIco != null ? 28 : 0), y + ((float) height / 2) + 1, textColor, fontSize, Fonts.INTER_MEDIUM);
+ if (fileNameLeftIco != null) {
+ RenderManager.drawImage(vg, fileNameLeftIco, middle - contentWidth / 2, y + 8, 20, 20);
+ }
+ if (fileNameRightIco != null) {
+ RenderManager.drawImage(vg, fileNameRightIco, middle + contentWidth / 2 - (fileNameLeftIco != null ? 20 : 24), y + 8, 20, 20);
+ }
+ }
+ if (thisAlignment == ALIGNMENT_LEFT) {
+ if (fileNameLeftIco != null) {
+ RenderManager.drawImage(vg, fileNameLeftIco, x + 12, y + 8, 20, 20, textColor);
+ RenderManager.drawString(vg, text, x + 40, y + ((float) height / 2) + 1, textColor, fontSize, Fonts.INTER_MEDIUM);
+ } else {
+ RenderManager.drawString(vg, text, x + 12, y + ((float) height / 2) + 1, textColor, fontSize, Fonts.INTER_MEDIUM);
+ }
+ if (fileNameRightIco != null) {
+ RenderManager.drawImage(vg, fileNameRightIco, x + width - 28, y + 8, 20, 20);
+ }
+ }
+ this.update(x, y);
+ if (hoverFx) {
+ if (colorPalette == -3) {
+ currentColor = OneConfigConfig.TRANSPARENT;
+ return;
+ }
+ if (!toggleable) {
+ currentColor = ColorUtils.getColor(currentColor, colorPalette, hovered, clicked);
+ } else {
+ if (toggled) {
+ currentColor = ColorUtils.smoothColor(currentColor, OneConfigConfig.GRAY_500, OneConfigConfig.BLUE_600, true, 30f);
+ } else currentColor = ColorUtils.getColor(currentColor, colorPalette, hovered, clicked);
+ }
+ }
+ }
+
+
+ @Override
+ public void onClick() {
+ if (this.page != null) {
+ OneConfigGui.INSTANCE.openPage(page);
+ } else if (this.runnable != null) {
+ runnable.run();
+ }
+ }
+
+ @Override
+ public void update(int x, int y) {
+ if (toggleable && toggled) return;
+ super.update(x, y);
+ }
+
+ public void setToggled(boolean state) {
+ this.toggled = state;
+ }
+
+ public Page getPage() {
+ return page;
+ }
+
+ public String getText() {
+ return text;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/BasicElement.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/BasicElement.java
new file mode 100644
index 0000000..80eec9b
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/BasicElement.java
@@ -0,0 +1,107 @@
+package cc.polyfrost.oneconfig.gui.elements;
+
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.utils.ColorUtils;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+
+public class BasicElement {
+ protected int width, height;
+ protected int colorPalette;
+ protected int hitBoxX, hitBoxY;
+ protected final boolean hoverFx;
+ protected boolean hovered = false;
+ protected boolean clicked = false;
+ protected boolean toggled = false;
+ protected boolean disabled = false;
+ protected int currentColor;
+
+ public BasicElement(int width, int height, int colorPalette, boolean hoverFx) {
+ this.height = height;
+ this.width = width;
+ this.colorPalette = colorPalette;
+ this.hoverFx = hoverFx;
+ }
+
+ public BasicElement(int width, int height, boolean hoverFx) {
+ this.height = height;
+ this.width = width;
+ this.colorPalette = -1;
+ this.hoverFx = hoverFx;
+ }
+
+
+ public void draw(long vg, int x, int y) {
+ RenderManager.drawRectangle(vg, x, y, width, height, currentColor);
+
+ update(x, y);
+ if (hoverFx) {
+ currentColor = ColorUtils.getColor(currentColor, colorPalette, hovered, clicked);
+ }
+ }
+
+ public void update(int x, int y) {
+ if(disabled) {
+ hovered = false;
+ clicked = false;
+ return;
+ }
+ hovered = InputUtils.isAreaHovered(x - hitBoxX, y - hitBoxY, width + hitBoxX, height + hitBoxY);
+ clicked = InputUtils.isClicked() && hovered;
+
+ if (hovered) {
+ if (clicked) {
+ toggled = !toggled;
+ onClick();
+ }
+ }
+ }
+
+
+ public void onClick() {
+
+ }
+
+ public void setCustomHitbox(int x, int y) {
+ hitBoxX = x;
+ hitBoxY = y;
+ }
+
+ public void setWidth(int width) {
+ this.width = width;
+ }
+
+ public void setHeight(int height) {
+ this.height = height;
+ }
+
+ public void setColorPalette(int colorPalette) {
+ this.colorPalette = colorPalette;
+ }
+
+ public int getWidth() {
+ return width;
+ }
+
+ public int getHeight() {
+ return height;
+ }
+
+ public boolean isHovered() {
+ return hovered;
+ }
+
+ public boolean isClicked() {
+ return clicked;
+ }
+
+ public boolean isToggled() {
+ return toggled;
+ }
+
+ public boolean isDisabled() {
+ return disabled;
+ }
+ public void disable(boolean state) {
+ disabled = state;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/ColorSelector.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/ColorSelector.java
new file mode 100644
index 0000000..83d0f7c
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/ColorSelector.java
@@ -0,0 +1,250 @@
+package cc.polyfrost.oneconfig.gui.elements;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import org.lwjgl.input.Mouse;
+
+import java.awt.*;
+import java.util.ArrayList;
+
+public class ColorSelector {
+ private Color color;
+ private final int x, y;
+ private final int width = 416;
+ private final int height = 768;
+
+ private final BasicElement HSBButton = new BasicElement(128, 32, -1, true);
+ private final BasicElement RGBButton = new BasicElement(128, 32, -1, true);
+ private final BasicElement ChromaButton = new BasicElement(128, 32, -1, true);
+
+ private final ArrayList<BasicElement> faves = new ArrayList<>();
+ private final ArrayList<BasicElement> history = new ArrayList<>();
+ private final BasicElement closeButton = new BasicElement(32, 32, -1, true);
+
+
+ public ColorSelector(Color color, int mouseX, int mouseY) {
+ this.color = color;
+ this.y = mouseY - 768;
+ this.x = mouseX - 208;
+
+ }
+
+ public void draw(long vg) {
+ RenderManager.drawRoundedRect(vg, x, y, width, height, OneConfigConfig.GRAY_800, 20f);
+
+ }
+
+ public Color getColor() {
+ return color;
+ }
+
+
+
+ private class HSBSelector extends ColorSelectorBase {
+
+
+ public HSBSelector(Color color) {
+ super(color);
+ }
+
+ @Override
+ public void drawBox(long vg, int x, int y) {
+
+ }
+
+ @Override
+ public void setColor(Color color) {
+
+ }
+
+ @Override
+ public int[] drawTopSlider() {
+ return new int[0];
+ }
+
+ @Override
+ public int[] drawBottomSlider() {
+ return new int[0];
+ }
+
+ @Override
+ public float[] getColorAtPos(int clickX, int clickY) {
+ return new float[0];
+ }
+ }
+
+
+ private class RGBSelector extends ColorSelectorBase {
+
+ public RGBSelector(Color color) {
+ super(color);
+ }
+
+ @Override
+ public void drawBox(long vg, int x, int y) {
+
+ }
+
+ @Override
+ public void setColor(Color color) {
+
+ }
+
+ @Override
+ public int[] drawTopSlider() {
+ return new int[0];
+ }
+
+ @Override
+ public int[] drawBottomSlider() {
+ return new int[0];
+ }
+
+
+ @Override
+ public float[] getColorAtPos(int clickX, int clickY) {
+ return new float[0];
+ }
+ }
+
+
+
+ private abstract class ColorSelectorBase {
+
+ private int selectedX;
+ private int selectedY;
+ private float[] hsb = new float[3];
+ private float[] rgba;
+ private final TextInputFieldNumber hueField = new TextInputFieldNumber(72, 32, "", 0, 100);
+ private final TextInputFieldNumber saturationField = new TextInputFieldNumber(72, 32, "", 0, 100);
+ private final TextInputFieldNumber brightnessField = new TextInputFieldNumber(72, 32, "", 0, 100);
+ private final TextInputFieldNumber alphaField = new TextInputFieldNumber(72, 32, "", 0, 100);
+
+ private final TextInputField hexField = new TextInputField(107, 32, true, false, "");
+ private final TextInputFieldNumber redField = new TextInputFieldNumber(44, 32, "", 0, 255);
+ private final TextInputFieldNumber greenField = new TextInputFieldNumber(44, 32, "", 0, 255);
+ private final TextInputFieldNumber blueField = new TextInputFieldNumber(44, 32, "", 0, 255);
+
+ private final Slider sliderTop = new Slider(0);
+ private final Slider sliderBottom = new Slider(0);
+
+ public ColorSelectorBase(Color color) {
+ rgba = new float[]{color.getRed() / 255f, color.getGreen() / 255f, color.getBlue() / 255f, color.getAlpha() / 255f};
+ }
+
+ public void updateElements(float[] rgba) {
+ this.rgba = rgba;
+ hsb = Color.RGBtoHSB((int) (rgba[0] * 255), (int) (rgba[1] * 255), (int) (rgba[2] * 255), hsb);
+ hueField.setInput(String.valueOf(hsb[0]));
+ saturationField.setInput(String.valueOf(hsb[1]));
+ brightnessField.setInput(String.valueOf(hsb[2]));
+ alphaField.setInput(String.valueOf(rgba[3]));
+ redField.setInput(String.valueOf(rgba[0]));
+ greenField.setInput(String.valueOf(rgba[1]));
+ blueField.setInput(String.valueOf(rgba[2]));
+ }
+ public abstract void drawBox(long vg, int x, int y);
+
+ /** draw the color selector contents, including the box, and the input fields. If it is clicked, getColorAtPos is called. updateElements is also called to update all the input fields. */
+ public void draw(long vg, int x, int y) {
+ drawBox(vg, x + 16, y + 120);
+ if(InputUtils.isAreaHovered(x + 16, y + 120, 384, 288) && Mouse.isButtonDown(0)) {
+ selectedX = InputUtils.mouseX() - x - 16;
+ selectedY = InputUtils.mouseY() - y - 120;
+ rgba = getColorAtPos(selectedX, selectedY);
+ } // TODO all of this
+ hueField.draw(vg, x + 104, y + 544);
+ saturationField.draw(vg, x + 312, y + 544);
+ brightnessField.draw(vg, x + 103, y + 584);
+ alphaField.draw(vg, x + 103, y + 584);
+ hexField.draw(vg, x + 96, y + 624);
+ redField.draw(vg, x + 228, y + 624);
+ greenField.draw(vg, x + 292, y + 664);
+ blueField.draw(vg, x + 356, y + 664);
+ sliderTop.draw(vg, x + 16, y + 424, drawTopSlider()[0], drawTopSlider()[1]);
+ sliderBottom.draw(vg, x + 16, y + 576, drawBottomSlider()[0], drawBottomSlider()[1]);
+ updateElements(rgba);
+ Color color1 = new Color(rgba[0], rgba[1], rgba[2], rgba[3]);
+ setColor(color1);
+ RenderManager.drawRoundedRect(vg, x + 16, y + 488, 384, 40, color1.getRGB(), 12f);
+ }
+
+ /** called to set the color of the color selector box based on the values of the input fields. */
+ public abstract void setColor(Color color);
+
+ /** return an array of two ints of the start color of the gradient and the end color of the gradient. */
+ public abstract int[] drawTopSlider();
+ /** return an array of two ints of the start color of the gradient and the end color of the gradient. */
+ public abstract int[] drawBottomSlider();
+
+ /**
+ * This method is called when the color selector is clicked. It needs to return color at the clicked position.
+ * @return color at the clicked position as a <code>float[] rgba.</code>
+ */
+ public abstract float[] getColorAtPos(int clickX, int clickY);
+
+ public float getRed() {
+ return rgba[0];
+ }
+ public float getGreen(){
+ return rgba[1];
+ }
+ public float getBlue(){
+ return rgba[2];
+ }
+ public float getAlpha(){
+ return rgba[3];
+ }
+
+ public float getHue(){
+ return hsb[0];
+ }
+
+ public float getSaturation(){
+ return hsb[1];
+ }
+
+ public float getBrightness(){
+ return hsb[2];
+ }
+
+ public String getHex() {
+ return null;
+ };
+
+ public Color getColor() {
+ return new Color(rgba[0], rgba[1], rgba[2], rgba[3]);
+ }
+
+ }
+
+ private class TextInputFieldNumber extends TextInputField {
+ private final float min, max;
+ public TextInputFieldNumber(int width, int height, String defaultValue, float min, float max) {
+ super(width, height, true, true, defaultValue);
+ this.min = min;
+ this.max = max;
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ super.draw(vg, x, y);
+
+ }
+ }
+
+ private class Slider {
+ private final int style;
+
+ public Slider(int style) {
+ this.style = style;
+ }
+
+ public void draw(long vg, int x, int y, int color1, int color2) {
+
+ }
+ }
+}
+
+
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/ModCard.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/ModCard.java
new file mode 100644
index 0000000..4fe1524
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/ModCard.java
@@ -0,0 +1,146 @@
+package cc.polyfrost.oneconfig.gui.elements;
+
+import cc.polyfrost.oneconfig.OneConfig;
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.data.Mod;
+import cc.polyfrost.oneconfig.config.data.ModType;
+import cc.polyfrost.oneconfig.gui.OneConfigGui;
+import cc.polyfrost.oneconfig.gui.pages.ModConfigPage;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+import cc.polyfrost.oneconfig.utils.ColorUtils;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import net.minecraft.client.Minecraft;
+import net.minecraft.command.CommandException;
+import net.minecraftforge.client.ClientCommandHandler;
+import net.minecraftforge.fml.common.ModMetadata;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.lwjgl.nanovg.NanoVG;
+
+import java.util.ArrayList;
+
+public class ModCard extends BasicElement {
+ private final String iconPath;
+ private final Mod modData;
+ private final BasicElement favoriteHitbox = new BasicElement(32, 32, -2, true);
+ private boolean active, disabled, favorite;
+ private int colorGray = OneConfigConfig.GRAY_600;
+ private int colorPrimary = OneConfigConfig.BLUE_600;
+ private boolean isHoveredMain = false;
+
+ public ModCard(@NotNull Mod mod, @Nullable String iconPath, boolean active, boolean disabled, boolean favorite) {
+ super(244, 119, false);
+ this.modData = mod;
+ this.iconPath = iconPath;
+ this.active = active;
+ toggled = active;
+ this.disabled = disabled;
+ this.favorite = favorite;
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ if (disabled) NanoVG.nvgGlobalAlpha(vg, 0.5f);
+ RenderManager.drawRoundedRectVaried(vg, x, y, width, 87, colorGray, 12f, 12f, 0f, 0f);
+ RenderManager.drawRoundedRectVaried(vg, x, y + 87, width, 32, colorPrimary, 0f, 0f, 12f, 12f);
+ RenderManager.drawLine(vg, x, y + 86, x + width, y + 86, 2, OneConfigConfig.GRAY_300);
+ if (iconPath != null) {
+ RenderManager.drawImage(vg, iconPath, x, y, width, 87);
+ } else {
+ RenderManager.drawImage(vg, Images.MOD_BOX, x + 98, y + 19, 48, 48);
+ }
+ favoriteHitbox.update(x + 212, y + 87);
+ favoriteHitbox.currentColor = ColorUtils.getColor(favoriteHitbox.currentColor, favoriteHitbox.colorPalette, favoriteHitbox.hovered, favoriteHitbox.clicked);
+ RenderManager.drawRoundedRectVaried(vg, x + 212, y + 87, 32, 32, favoriteHitbox.currentColor, 0f, 0f, 12f, 0f);
+ favorite = favoriteHitbox.isToggled();
+ RenderManager.drawString(vg, modData.name, x + 12, y + 103, OneConfigConfig.WHITE, 14f, Fonts.INTER_MEDIUM);
+ if (favorite) {
+ RenderManager.drawImage(vg, Images.FAVORITE, x + 220, y + 95, 16, 16);
+ } else {
+ RenderManager.drawImage(vg, Images.FAVORITE_OFF, x + 220, y + 95, 16, 16);
+ }
+ super.update(x, y);
+ isHoveredMain = InputUtils.isAreaHovered(x, y, width, 87);
+ boolean isHoveredSecondary = InputUtils.isAreaHovered(x, y + 87, width - 32, 32) && !disabled;
+ colorGray = ColorUtils.getColor(colorGray, 0, isHoveredMain, clicked && isHoveredMain);
+ if (active && !disabled) {
+ colorPrimary = ColorUtils.getColor(colorPrimary, 1, isHoveredSecondary, clicked && isHoveredSecondary);
+ } else
+ colorPrimary = ColorUtils.smoothColor(colorPrimary, OneConfigConfig.GRAY_500, OneConfigConfig.GRAY_400, isHoveredSecondary, 20f);
+
+ if (clicked && isHoveredMain) {
+ if (!active) toggled = false;
+ }
+ if (clicked && favoriteHitbox.hovered) toggled = false;
+ if (clicked && !isHoveredSecondary && active) toggled = true;
+ if (!active & disabled) toggled = false;
+ //RenderManager.drawString(vg, "active=" + active, x + 150, y + 92, OneConfigConfig.WHITE, 10f, Fonts.INTER_MEDIUM); // debug stuff
+ //RenderManager.drawString(vg, "disabled=" + disabled, x + 150, y + 103, OneConfigConfig.WHITE, 10f, Fonts.INTER_MEDIUM);
+ //RenderManager.drawString(vg, "favorite=" + favorite, x + 150, y + 114, OneConfigConfig.WHITE, 10f, Fonts.INTER_MEDIUM);
+
+
+ active = toggled;
+ NanoVG.nvgGlobalAlpha(vg, 1f);
+ }
+
+ public void onClick() {
+ if (isHoveredMain) {
+ for (Mod data : OneConfig.loadedMods) {
+ if (data.modType != ModType.OTHER) {
+ if (data.name.equalsIgnoreCase(modData.name)) {
+ OneConfigGui.INSTANCE.openPage(new ModConfigPage(data.defaultPage));
+ }
+ }
+ }
+ for (ModMetadata mod : OneConfig.loadedOtherMods) {
+ if (mod.name.equalsIgnoreCase(modData.name)) {
+ ArrayList<String> possibleCommands = new ArrayList<>();
+ possibleCommands.add(mod.name.toLowerCase().replace(" ", ""));
+ possibleCommands.add(mod.modId.toLowerCase().replaceAll("[ -_]", ""));
+ if (mod.name.split(" ").length > 1) {
+ StringBuilder result = new StringBuilder();
+ for (String word : mod.name.split(" ")) {
+ if (word.length() == 0) continue;
+ result.append(word.charAt(0));
+ }
+ possibleCommands.add(result.toString().toLowerCase());
+ }
+ for (String command : ClientCommandHandler.instance.getCommands().keySet()) {
+ if (possibleCommands.contains(command)) {
+ try {
+ ClientCommandHandler.instance.getCommands().get(command).processCommand(Minecraft.getMinecraft().thePlayer, new String[]{});
+ } catch (CommandException e) {
+ throw new RuntimeException(e);
+ }
+ break;
+ }
+ }
+ return;
+ }
+
+ }
+ }
+ }
+
+ public Mod getModData() {
+ return modData;
+ }
+
+ public boolean isDisabled() {
+ return disabled;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public void setDisabled(boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ public boolean isFavorite() {
+ return favorite;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/SearchField.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/SearchField.java
new file mode 100644
index 0000000..6f460d6
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/SearchField.java
@@ -0,0 +1,14 @@
+package cc.polyfrost.oneconfig.gui.elements;
+
+public class SearchField extends TextInputField {
+
+ public SearchField(int width, int height, String defaultText, boolean multiLine, boolean password) {
+ super(width, height, defaultText, multiLine, password);
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ super.draw(vg, x, y);
+ // TODO
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/TextInputField.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/TextInputField.java
new file mode 100644
index 0000000..3058643
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/TextInputField.java
@@ -0,0 +1,418 @@
+package cc.polyfrost.oneconfig.gui.elements;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.Scissor;
+import cc.polyfrost.oneconfig.lwjgl.ScissorManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import net.minecraft.client.gui.GuiScreen;
+import net.minecraft.util.ChatAllowedCharacters;
+import org.jetbrains.annotations.NotNull;
+import org.lwjgl.input.Keyboard;
+import org.lwjgl.input.Mouse;
+
+import java.awt.*;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+
+public class TextInputField extends BasicElement {
+
+ protected final String defaultText;
+ protected String input, selectedText;
+ protected final boolean multiLine;
+ protected boolean password;
+
+ protected int caretPos;
+ protected int x, y;
+ protected float start, end;
+ private long clickTimeD1;
+ protected long vg;
+ protected int prevCaret = 0;
+ protected boolean isDoubleClick = false;
+ protected boolean onlyNums = false;
+ protected boolean errored = false;
+ protected boolean centered = false;
+
+ public TextInputField(int width, int height, String defaultText, boolean multiLine, boolean password) {
+ super(width, height, false);
+ this.multiLine = multiLine;
+ this.defaultText = defaultText;
+ this.password = password;
+ this.input = "";
+ }
+
+ public TextInputField(int width, int height, boolean centered, boolean onlyNums, String defaultText) {
+ this(width, height, defaultText, false, false);
+ this.centered = centered;
+ this.onlyNums = onlyNums;
+ }
+
+ public void onlyAcceptNumbers(boolean state) {
+ onlyNums = state;
+ }
+
+ public void setInput(String input) {
+ this.input = input;
+ }
+
+ public String getInput() {
+ return input;
+ }
+
+ public void setPassword(boolean password) {
+ this.password = password;
+ }
+
+ public boolean getPassword() {
+ return password;
+ }
+
+ public void setErrored(boolean errored) {
+ this.errored = errored;
+ }
+
+ public void setCentered(boolean centered) {
+ this.centered = centered;
+ }
+
+ public boolean isErrored() {
+ return errored;
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ this.x = x;
+ this.y = y;
+ this.vg = vg;
+ try {
+ Scissor scissor = ScissorManager.scissor(vg, x, y, width, height);
+ int colorOutline = errored ? OneConfigConfig.ERROR_700 : OneConfigConfig.GRAY_700;
+ RenderManager.drawHollowRoundRect(vg, x, y, width, height, colorOutline, 12f, 2f);
+ super.update(x, y);
+ if (Mouse.isButtonDown(0) && !InputUtils.isAreaHovered(x - 40, y - 20, width + 90, height + 20)) {
+ toggled = false;
+ }
+ int color = toggled ? OneConfigConfig.WHITE : OneConfigConfig.WHITE_60;
+ if (!toggled) caretPos = input.length();
+ float width;
+ StringBuilder s = new StringBuilder();
+ if (!password) {
+ width = RenderManager.getTextWidth(vg, input.substring(0, caretPos), 14f, Fonts.INTER_REGULAR);
+ } else {
+ for (int i = 0; i < input.length(); i++) {
+ s.append("*");
+ }
+ width = RenderManager.getTextWidth(vg, s.substring(0, caretPos), 14f, Fonts.INTER_REGULAR);
+ }
+ if (hovered) {
+ while (Mouse.next()) {
+ if (Mouse.getEventButtonState()) {
+ if (Mouse.getEventButton() == 0) {
+ prevCaret = calculatePos(Mouse.getX());
+ if (System.currentTimeMillis() - clickTimeD1 < 300) {
+ onDoubleClick();
+ isDoubleClick = true;
+ }
+ clickTimeD1 = System.currentTimeMillis();
+ }
+ } else {
+ if (Mouse.getEventButton() == 0) {
+ long clickTimeU = System.currentTimeMillis();
+ if (clickTimeU - clickTimeD1 < 200) {
+ if (!isDoubleClick) {
+ start = 0;
+ end = 0;
+ }
+ prevCaret = caretPos;
+ isDoubleClick = false;
+ }
+
+ }
+ }
+ }
+ }
+ float halfTextWidth = this.getTextWidth(vg, input) / 2f;
+ if (start != 0f && end != 0f && toggled) {
+ RenderManager.drawRect(vg, start, y + height / 2f - 10, end, 20, OneConfigConfig.GRAY_300);
+ }
+ if (hovered) {
+ if (Mouse.isButtonDown(0) && !isDoubleClick) {
+ caretPos = calculatePos(Mouse.getX());
+ if (caretPos > prevCaret) {
+ if (!centered) start = x + 12 + this.getTextWidth(vg, input.substring(0, prevCaret));
+ else
+ start = x + this.width / 2f - halfTextWidth + this.getTextWidth(vg, input.substring(0, prevCaret));
+ end = this.getTextWidth(vg, input.substring(prevCaret, caretPos));
+ selectedText = input.substring(prevCaret, caretPos);
+ } else {
+ if (!centered) start = x + 12 + this.getTextWidth(vg, input.substring(0, prevCaret));
+ else
+ start = x + this.width / 2f - halfTextWidth + this.getTextWidth(vg, input.substring(0, prevCaret));
+ end = -this.getTextWidth(vg, input.substring(caretPos, prevCaret));
+ selectedText = input.substring(caretPos, prevCaret);
+ }
+ }
+ }
+
+
+ if (toggled) {
+ if (!centered) {
+ RenderManager.drawLine(vg, x + width + 12, (float) y + height / 2f - 10, x + width + 12, (float) y + height / 2f + 10, 1, OneConfigConfig.WHITE);
+ } else {
+ RenderManager.drawLine(vg, x + this.width / 2f - halfTextWidth + width, (float) y + height / 2f - 10, x + this.width / 2f - halfTextWidth + width, (float) y + height / 2f + 10, 1, OneConfigConfig.WHITE);
+ }
+ }
+
+
+ if (input.equals("")) {
+ if (!centered) {
+ RenderManager.drawString(vg, defaultText, x + 12, y + height / 2f + 1, color, 14f, Fonts.INTER_REGULAR);
+ } else {
+ RenderManager.drawString(vg, defaultText, x + this.width / 2f - halfTextWidth, y + height / 2f + 1, color, 14f, Fonts.INTER_REGULAR);
+ }
+ }
+
+ if (!password) {
+ if (!centered) {
+ RenderManager.drawString(vg, input, x + 12, y + height / 2f + 1, color, 14f, Fonts.INTER_REGULAR);
+ } else {
+ RenderManager.drawString(vg, input, x + this.width / 2f - halfTextWidth, y + height / 2f + 1, color, 14f, Fonts.INTER_REGULAR);
+ }
+ } else {
+ RenderManager.drawString(vg, s.toString(), x + 12, y + height / 2f + 1, color, 14f, Fonts.INTER_REGULAR);
+ }
+ ScissorManager.resetScissor(vg, scissor);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void keyTyped(char c, int key) {
+ try {
+ if (toggled) {
+ if (GuiScreen.isKeyComboCtrlC(key)) {
+ if (selectedText != null && start != 0f && end != 0f) {
+ Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(selectedText), null);
+ }
+ return;
+ }
+ if (GuiScreen.isKeyComboCtrlV(key) || key == Keyboard.KEY_INSERT) {
+ try {
+ String clip = Toolkit.getDefaultToolkit().getSystemClipboard().getContents(null).getTransferData(DataFlavor.stringFlavor).toString();
+ input = input.substring(0, caretPos) + clip + input.substring(caretPos);
+ caretPos = caretPos + clip.length();
+ return;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (key == Keyboard.KEY_DELETE) {
+ input = "";
+ }
+
+
+ if (GuiScreen.isCtrlKeyDown()) {
+ if (key == Keyboard.KEY_BACK && !GuiScreen.isKeyComboCtrlX(key)) {
+ try {
+ input = input.substring(0, input.lastIndexOf(" "));
+ caretPos = input.length();
+ } catch (Exception e) {
+ input = "";
+ caretPos = 0;
+ }
+ return;
+ }
+ if (GuiScreen.isKeyComboCtrlA(key)) {
+ prevCaret = 0;
+ caretPos = input.length();
+ start = !centered ? x + 12 : x + this.width / 2f - this.getTextWidth(vg, input) / 2f;
+ selectedText = input;
+ end = this.getTextWidth(vg, input);
+ return;
+ }
+ if (GuiScreen.isKeyComboCtrlX(key)) {
+ if (selectedText != null && start != 0f && end != 0f) {
+ Toolkit.getDefaultToolkit().getSystemClipboard().setContents(new StringSelection(selectedText), null);
+ key = Keyboard.KEY_BACK;
+ } else return;
+ }
+ if (key == Keyboard.KEY_LEFT) {
+ caretPos = input.substring(0, caretPos).lastIndexOf(' ') + 1;
+ }
+ if (key == Keyboard.KEY_RIGHT) {
+ caretPos = input.indexOf(' ', caretPos);
+ if (caretPos == -1) caretPos = input.length();
+ }
+
+ }
+ if (key == Keyboard.KEY_BACK) {
+ if (input.length() > 0) {
+ if (start != 0f && end != 0f) {
+ start = 0f;
+ end = 0f;
+ if (caretPos > prevCaret) {
+ input = input.substring(0, prevCaret) + input.substring(caretPos);
+ caretPos = prevCaret;
+ }
+ if (caretPos < prevCaret) {
+ input = input.substring(0, caretPos) + input.substring(prevCaret);
+ }
+ return;
+ }
+ if (caretPos == input.length()) {
+ input = input.substring(0, input.length() - 1);
+ } else {
+ input = input.substring(0, caretPos - 1) + input.substring(caretPos);
+ }
+ caretPos--;
+ }
+ return;
+ }
+ if (key == Keyboard.KEY_TAB) {
+ if (onlyNums) return;
+ input += " ";
+ caretPos += 4;
+ return;
+ }
+
+ if (key == Keyboard.KEY_RIGHT) {
+ caretPos++;
+ if (caretPos > input.length()) {
+ caretPos = input.length();
+ }
+ if (start != 0f && end != 0f) {
+ start = 0f;
+ end = 0f;
+ }
+ return;
+ }
+ if (key == Keyboard.KEY_LEFT) {
+ caretPos--;
+ if (caretPos < 0) {
+ caretPos = 0;
+ }
+ if (start != 0f && end != 0f) {
+ start = 0f;
+ end = 0f;
+ }
+ return;
+ }
+ if (key == Keyboard.KEY_UP || key == 201) { // 201 = page up
+ caretPos = 0;
+ if (start != 0f && end != 0f) {
+ start = 0f;
+ end = 0f;
+ }
+ return;
+ }
+ if (key == Keyboard.KEY_DOWN || key == 209) { // 209 = page down
+ caretPos = input.length();
+ if (start != 0f && end != 0f) {
+ start = 0f;
+ end = 0f;
+ }
+ return;
+ }
+
+
+ if (key == Keyboard.KEY_RETURN) {
+ toggled = false;
+ if (start != 0f && end != 0f) {
+ start = 0f;
+ end = 0f;
+ }
+ }
+ if (key == Keyboard.KEY_END) {
+ toggled = false;
+ }
+
+
+ if (key == Keyboard.KEY_LCONTROL || key == Keyboard.KEY_RCONTROL || key == Keyboard.KEY_LMENU || key == Keyboard.KEY_RMENU || key == Keyboard.KEY_LMETA || key == Keyboard.KEY_RMETA || key == Keyboard.KEY_LSHIFT || key == Keyboard.KEY_RSHIFT || key == Keyboard.KEY_RETURN || key == Keyboard.KEY_CAPITAL || key == 221 || key == Keyboard.KEY_HOME) {
+ return;
+ }
+ if (onlyNums) {
+ if (!Character.isDigit(c) && key != 52) return;
+ }
+ if (!Character.isDefined(key)) return;
+ if (!Character.isDefined(c)) return;
+ if (GuiScreen.isCtrlKeyDown()) return;
+ if (ChatAllowedCharacters.isAllowedCharacter(c)) {
+ if (selectedText != null) {
+ if (caretPos > prevCaret) {
+ input = input.substring(0, prevCaret) + input.substring(prevCaret, caretPos);
+ caretPos = prevCaret;
+ } else {
+ input = input.substring(0, caretPos) + input.substring(caretPos, prevCaret);
+ }
+ if (selectedText.equals(input)) {
+ input = "";
+ }
+ selectedText = null;
+ }
+ input = addCharAtPoint(caretPos, c);
+ caretPos++;
+ }
+ if (start != 0f && end != 0f) {
+ start = 0f;
+ end = 0f;
+ }
+
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ private @NotNull String addCharAtPoint(int index, char c) {
+ return input.substring(0, index) + c + input.substring(index);
+ }
+
+ @Override
+ public void onClick() {
+ toggled = true;
+ }
+
+ private void onDoubleClick() {
+ prevCaret = input.substring(0, caretPos).lastIndexOf(' ') + 1;
+ caretPos = input.indexOf(' ', caretPos);
+ if (caretPos == -1) caretPos = input.length();
+ selectedText = input.substring(prevCaret, caretPos);
+ if (!centered) start = x + 12 + this.getTextWidth(vg, input.substring(0, prevCaret));
+ else
+ start = x + this.width / 2f - this.getTextWidth(vg, input) / 2f + this.getTextWidth(vg, input.substring(0, prevCaret));
+ end = this.getTextWidth(vg, input.substring(prevCaret, caretPos));
+ }
+
+ private int calculatePos(int pos) {
+ if (centered) pos -= 12;
+ String s1 = "";
+ int i;
+ for (char c : input.toCharArray()) {
+ if (pos - x - 12 < 0) {
+ return 0;
+ }
+ if (pos - x - 12 > this.getTextWidth(vg, input)) {
+ return input.length();
+ }
+ s1 += c;
+ i = (int) this.getTextWidth(vg, s1);
+ if (i >= pos - x - 16) {
+ return s1.length();
+ }
+ }
+ return 0;
+ }
+
+ private float getTextWidth(long vg, String s) {
+ if (password) {
+ StringBuilder s1 = new StringBuilder();
+ while (s1.length() < s.length()) {
+ s1.append('*');
+ }
+ return RenderManager.getTextWidth(vg, s1.toString(), 14.0f, Fonts.INTER_REGULAR);
+ } else {
+ return RenderManager.getTextWidth(vg, s, 14.0f, Fonts.INTER_REGULAR);
+ }
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigCheckbox.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigCheckbox.java
new file mode 100644
index 0000000..990ce07
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigCheckbox.java
@@ -0,0 +1,61 @@
+package cc.polyfrost.oneconfig.gui.elements.config;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.interfaces.BasicOption;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+import cc.polyfrost.oneconfig.utils.ColorUtils;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import cc.polyfrost.oneconfig.utils.MathUtils;
+
+import java.awt.*;
+import java.lang.reflect.Field;
+
+public class ConfigCheckbox extends BasicOption {
+ private int color;
+ private float percentOn = 0f;
+
+ public ConfigCheckbox(Field field, String name, int size) {
+ super(field, name, size);
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ boolean toggled = false;
+ try {
+ toggled = (boolean) get();
+ } catch (IllegalAccessException ignored) {
+ }
+ boolean hover = InputUtils.isAreaHovered(x, y + 4, 24, 24);
+
+ boolean clicked = InputUtils.isClicked() && hover;
+ if (clicked) {
+ toggled = !toggled;
+ try {
+ set(toggled);
+ } catch (IllegalAccessException e) {
+ System.err.println("failed to write config value: class=" + this + " fieldWatching=" + field + " valueWrite=" + toggled);
+ e.printStackTrace();
+ }
+ }
+ if (percentOn != 1f) { // performance
+ RenderManager.drawRoundedRect(vg, x, y + 4, 24, 24, color, 6f);
+ RenderManager.drawHollowRoundRect(vg, x, y + 4, 23.5f, 23.5f, OneConfigConfig.GRAY_300, 6f, 1f); // the 0.5f is to make it look better ok
+ }
+ color = ColorUtils.smoothColor(color, OneConfigConfig.GRAY_600, OneConfigConfig.GRAY_400, hover, 40f);
+ RenderManager.drawString(vg, name, x + 32, y + 17, OneConfigConfig.WHITE_90, 14f, Fonts.INTER_MEDIUM);
+ percentOn = MathUtils.clamp(MathUtils.easeOut(percentOn, toggled ? 1f : 0f, 5f));
+ if (percentOn == 0f) return;
+ if (percentOn != 1f) {
+ RenderManager.drawImage(vg, Images.CHECKMARK, x, y + 4, 24, 24, new Color(1f, 1f, 1f, percentOn).getRGB());
+ } else { // performance, that color could cause havoc am I right definitely
+ RenderManager.drawImage(vg, Images.CHECKMARK, x, y + 4, 24, 24);
+ }
+ }
+
+ @Override
+ public int getHeight() {
+ return 32;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigColorElement.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigColorElement.java
new file mode 100644
index 0000000..2c89133
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigColorElement.java
@@ -0,0 +1,115 @@
+package cc.polyfrost.oneconfig.gui.elements.config;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.interfaces.BasicOption;
+import cc.polyfrost.oneconfig.gui.OneConfigGui;
+import cc.polyfrost.oneconfig.gui.elements.BasicElement;
+import cc.polyfrost.oneconfig.gui.elements.ColorSelector;
+import cc.polyfrost.oneconfig.gui.elements.TextInputField;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+
+import java.awt.*;
+import java.lang.reflect.Field;
+
+public class ConfigColorElement extends BasicOption {
+ private float alpha;
+ private Color color = Color.BLUE;
+ private String hex;
+
+ private final TextInputField hexField = new TextInputField(104, 32, "", false, false);
+ private final TextInputField alphaField = new TextInputField(72, 32, "", false, false);
+ private final BasicElement element = new BasicElement(64, 32, false);
+
+ public ConfigColorElement(Field field, String name, int size) {
+ super(field, name, size);
+ hexField.setCentered(true);
+ alphaField.setCentered(true);
+ alphaField.onlyAcceptNumbers(true);
+ String buf = Integer.toHexString(color.getRGB());
+ hex = "#"+buf.substring(buf.length()-6);
+ }
+
+ @Override
+ public int getHeight() {
+ return 32;
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ RenderManager.drawString(vg, name, x, y + 15, OneConfigConfig.WHITE_90, 18f, Fonts.INTER_MEDIUM);
+ hexField.draw(vg, x + 240, y);
+
+ if (!alphaField.isToggled()) alphaField.setInput(String.format("%.01f", alpha * 100f) + "%");
+ alphaField.setErrored(false);
+ if(alphaField.isToggled()) {
+ try {
+ float input = Float.parseFloat(alphaField.getInput());
+ if (input < 0f) {
+ alphaField.setErrored(true);
+ input = 100f;
+ }
+ if (input > 100f) {
+ alphaField.setErrored(true);
+ input = 100f;
+ }
+ alpha = input / 100f;
+ } catch (NumberFormatException e) {
+ alphaField.setErrored(true);
+ }
+ }
+ alphaField.draw(vg, x + 352, y);
+
+
+
+ if (!hexField.isToggled()) hexField.setInput(hex);
+ hexField.setErrored(false);
+ if(hexField.isToggled()) {
+ try {
+ color = HexToColor(hexField.getInput());
+ String buf = Integer.toHexString(color.getRGB());
+ hex = "#"+buf.substring(buf.length()-6);
+ } catch (NumberFormatException e) {
+ hexField.setErrored(true);
+ }
+ }
+ hexField.draw(vg, x + 352, y);
+
+ element.update(x + 432, y);
+ RenderManager.drawRoundedRect(vg, x + 432, y, 64, 32, OneConfigConfig.GRAY_300, 12f);
+ RenderManager.drawImage(vg, Images.COLOR_BASE, x + 948, y + 4, 56, 24, color.getRGB());
+ if(element.isClicked() && !element.isToggled()) {
+ OneConfigGui.INSTANCE.initColorSelector(new ColorSelector(color, InputUtils.mouseX(), InputUtils.mouseY()));
+ }
+ if(element.isToggled() && element.isClicked()) {
+ color = OneConfigGui.INSTANCE.closeColorSelector();
+ alpha = color.getAlpha() / 255f;
+ String buf = Integer.toHexString(color.getRGB());
+ hex = "#"+buf.substring(buf.length()-6);
+ }
+
+ }
+
+ // thanks stack overflow
+ public static Color HexToColor(String hex) throws NumberFormatException {
+ hex = hex.replace("#", "");
+ switch (hex.length()) {
+ case 6:
+ return new Color(
+ Integer.valueOf(hex.substring(0, 2), 16),
+ Integer.valueOf(hex.substring(2, 4), 16),
+ Integer.valueOf(hex.substring(4, 6), 16));
+ case 8:
+ return new Color(
+ Integer.valueOf(hex.substring(0, 2), 16),
+ Integer.valueOf(hex.substring(2, 4), 16),
+ Integer.valueOf(hex.substring(4, 6), 16),
+ Integer.valueOf(hex.substring(6, 8), 16));
+ }
+ throw new NumberFormatException("Invalid hex string: " + hex);
+ }
+
+
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigDropdown.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigDropdown.java
new file mode 100644
index 0000000..c867409
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigDropdown.java
@@ -0,0 +1,167 @@
+package cc.polyfrost.oneconfig.gui.elements.config;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.interfaces.BasicOption;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+import cc.polyfrost.oneconfig.utils.ColorUtils;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.nanovg.NanoVG;
+
+import java.awt.*;
+import java.lang.reflect.Field;
+import java.util.Arrays;
+
+public class ConfigDropdown extends BasicOption { // TODO: chose where dividers are somehow idfk please send help
+ private final String[] options;
+ private int backgroundColor = OneConfigConfig.GRAY_500;
+ private boolean opened = false;
+ private int[] dividers;
+
+ public ConfigDropdown(Field field, String name, int size, String[] options, int [] dividers) {
+ super(field, name, size);
+ this.options = options;
+ this.dividers = dividers;
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ RenderManager.drawString(vg, name, x, y + 16, OneConfigConfig.WHITE_90, 14f, Fonts.INTER_MEDIUM);
+
+ boolean hovered;
+ if (size == 1) hovered = InputUtils.isAreaHovered(x + 224, y, 256, 32);
+ else hovered = InputUtils.isAreaHovered(x + 352, y, 640, 32);
+
+ if (hovered && InputUtils.isClicked() || opened && InputUtils.isClicked() &&
+ (size == 1 && !InputUtils.isAreaHovered(x + 224, y + 40, 256, options.length * 32 + 4) ||
+ size == 2 && !InputUtils.isAreaHovered(x + 352, y + 40, 640, options.length * 32 + 4)))
+ opened = !opened;
+ if (opened) return;
+
+ backgroundColor = ColorUtils.smoothColor(backgroundColor, OneConfigConfig.GRAY_500, OneConfigConfig.GRAY_400, hovered, 100);
+ int selected = 0;
+ try {
+ selected = (int) get();
+ } catch (IllegalAccessException ignored) {
+ }
+
+ if (hovered && Mouse.isButtonDown(0)) NanoVG.nvgGlobalAlpha(vg, 0.8f);
+ if (size == 1) {
+ RenderManager.drawRoundedRect(vg, x + 224, y, 256, 32, backgroundColor, 12);
+ RenderManager.drawString(vg, options[selected], x + 236, y + 16, OneConfigConfig.WHITE_80, 14f, Fonts.INTER_MEDIUM);
+ RenderManager.drawRoundedRect(vg, x + 452, y + 4, 24, 24, OneConfigConfig.BLUE_600, 8);
+ RenderManager.drawImage(vg, Images.DROPDOWN_ARROW, x + 459, y + 8, 10, 6);
+ NanoVG.nvgTranslate(vg, x + 469, y + 24);
+ } else {
+ RenderManager.drawRoundedRect(vg, x + 352, y, 640, 32, backgroundColor, 12);
+ RenderManager.drawString(vg, options[selected], x + 364, y + 16, OneConfigConfig.WHITE_80, 14f, Fonts.INTER_MEDIUM);
+ RenderManager.drawRoundedRect(vg, x + 964, y + 4, 24, 24, OneConfigConfig.BLUE_600, 8);
+ RenderManager.drawImage(vg, Images.DROPDOWN_ARROW, x + 971, y + 8, 10, 6);
+ NanoVG.nvgTranslate(vg, x + 981, y + 24);
+ }
+ NanoVG.nvgRotate(vg, (float) Math.toRadians(180));
+ RenderManager.drawImage(vg, Images.DROPDOWN_ARROW, 0, 0, 10, 6);
+ NanoVG.nvgResetTransform(vg);
+ NanoVG.nvgGlobalAlpha(vg, 1f);
+ }
+
+ @Override
+ public void drawLast(long vg, int x, int y) {
+ if (!opened) return;
+
+ boolean hovered;
+ if (size == 1) hovered = InputUtils.isAreaHovered(x + 224, y, 256, 32);
+ else hovered = InputUtils.isAreaHovered(x + 352, y, 640, 32);
+
+ backgroundColor = ColorUtils.smoothColor(backgroundColor, OneConfigConfig.BLUE_800, OneConfigConfig.BLUE_700, hovered, 100);
+ int selected = 0;
+ try {
+ selected = (int) get();
+ } catch (IllegalAccessException ignored) {
+ }
+
+ if (hovered && Mouse.isButtonDown(0)) NanoVG.nvgGlobalAlpha(vg, 0.8f);
+ if (size == 1) {
+ RenderManager.drawRoundedRect(vg, x + 224, y, 256, 32, backgroundColor, 12);
+ RenderManager.drawString(vg, options[selected], x + 236, y + 16, OneConfigConfig.WHITE_80, 14f, Fonts.INTER_MEDIUM);
+
+ NanoVG.nvgGlobalAlpha(vg, 1f);
+ RenderManager.drawRoundedRect(vg, x + 224, y + 40, 256, options.length * 32 + 4, OneConfigConfig.GRAY_700, 12);
+ RenderManager.drawHollowRoundRect(vg, x + 224, y + 40, 256, options.length * 32 + 4, new Color(204, 204, 204, 77).getRGB(), 8, 1);
+ int optionY = y + 56;
+ for (String option : options) {
+ int color = OneConfigConfig.WHITE_80;
+ boolean optionHovered = InputUtils.isAreaHovered(x + 224, optionY - 16, 252, 32);
+ if (optionHovered && Mouse.isButtonDown(0)) {
+ RenderManager.drawRoundedRect(vg, x + 228, optionY - 12, 248, 28, OneConfigConfig.BLUE_700_80, 8);
+ } else if (optionHovered) {
+ RenderManager.drawRoundedRect(vg, x + 228, optionY - 12, 248, 28, OneConfigConfig.BLUE_700, 8);
+ color = OneConfigConfig.WHITE;
+ }
+ if (optionHovered && InputUtils.isClicked()) {
+ try {
+ set(Arrays.asList(options).indexOf(option));
+ } catch (IllegalAccessException ignored) {
+ }
+ opened = false;
+ }
+
+ RenderManager.drawString(vg, option, x + 240, optionY + 4, color, 14, Fonts.INTER_MEDIUM);
+ if (!options[options.length - 1].equals(option))
+ RenderManager.drawLine(vg, x + 232, optionY + 18, x + 472, optionY + 18, 1, new Color(204, 204, 204, 77).getRGB());
+ optionY += 32;
+ }
+
+ if (hovered && Mouse.isButtonDown(0)) NanoVG.nvgGlobalAlpha(vg, 0.8f);
+ RenderManager.drawRoundedRect(vg, x + 452, y + 4, 24, 24, OneConfigConfig.BLUE_600, 8);
+ RenderManager.drawImage(vg, Images.DROPDOWN_ARROW, x + 459, y + 8, 10, 6);
+ NanoVG.nvgTranslate(vg, x + 469, y + 24);
+ } else {
+ RenderManager.drawRoundedRect(vg, x + 352, y, 640, 32, backgroundColor, 12);
+ RenderManager.drawString(vg, options[selected], x + 364, y + 16, OneConfigConfig.WHITE_80, 14f, Fonts.INTER_MEDIUM);
+
+ RenderManager.drawRoundedRect(vg, x + 352, y + 40, 640, options.length * 32 + 4, OneConfigConfig.GRAY_700, 12);
+ RenderManager.drawHollowRoundRect(vg, x + 352, y + 40, 640, options.length * 32 + 4, new Color(204, 204, 204, 77).getRGB(), 8, 1);
+ int optionY = y + 56;
+ for (String option : options) {
+ int color = OneConfigConfig.WHITE_80;
+ boolean optionHovered = InputUtils.isAreaHovered(x + 352, optionY - 16, 640, 32);
+ if (optionHovered && Mouse.isButtonDown(0)) {
+ RenderManager.drawRoundedRect(vg, x + 356, optionY - 12, 632, 28, OneConfigConfig.BLUE_700_80, 8);
+ } else if (optionHovered) {
+ RenderManager.drawRoundedRect(vg, x + 356, optionY - 12, 632, 28, OneConfigConfig.BLUE_700, 8);
+ color = OneConfigConfig.WHITE;
+ }
+
+ RenderManager.drawString(vg, option, x + 368, optionY + 4, color, 14, Fonts.INTER_MEDIUM);
+ if (!options[options.length - 1].equals(option))
+ RenderManager.drawLine(vg, x + 360, optionY + 18, x + 984, optionY + 18, 1, new Color(204, 204, 204, 77).getRGB());
+
+ if (optionHovered && InputUtils.isClicked()) {
+ try {
+ set(Arrays.asList(options).indexOf(option));
+ } catch (IllegalAccessException ignored) {
+ }
+ opened = false;
+ }
+ optionY += 32;
+ }
+
+ if (hovered && Mouse.isButtonDown(0)) NanoVG.nvgGlobalAlpha(vg, 0.8f);
+ RenderManager.drawRoundedRect(vg, x + 964, y + 4, 24, 24, OneConfigConfig.BLUE_600, 8);
+ RenderManager.drawImage(vg, Images.DROPDOWN_ARROW, x + 971, y + 8, 10, 6);
+ NanoVG.nvgTranslate(vg, x + 981, y + 24);
+ }
+ NanoVG.nvgRotate(vg, (float) Math.toRadians(180));
+ RenderManager.drawImage(vg, Images.DROPDOWN_ARROW, 0, 0, 10, 6);
+ NanoVG.nvgResetTransform(vg);
+ NanoVG.nvgGlobalAlpha(vg, 1f);
+ }
+
+ @Override
+ public int getHeight() {
+ return 32;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigDualOption.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigDualOption.java
new file mode 100644
index 0000000..ed908b6
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigDualOption.java
@@ -0,0 +1,53 @@
+package cc.polyfrost.oneconfig.gui.elements.config;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.interfaces.BasicOption;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import cc.polyfrost.oneconfig.utils.MathUtils;
+
+import java.lang.reflect.Field;
+
+public class ConfigDualOption extends BasicOption {
+ private float percentMove = 0f;
+ private final String left, right;
+
+ public ConfigDualOption(Field field, String name, int size, String[] options) {
+ super(field, name, size);
+ this.left = options[0];
+ this.right = options[1];
+
+ }
+
+ @Override
+ public int getHeight() {
+ return 32;
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ boolean toggled = false;
+ try {
+ toggled = (boolean) get();
+ } catch (IllegalAccessException ignored) {
+ }
+ RenderManager.drawString(vg, name, x, y + 16, OneConfigConfig.WHITE_90, 14f, Fonts.INTER_MEDIUM);
+ RenderManager.drawRoundedRect(vg, x + 226, y, 256, 32, OneConfigConfig.GRAY_500, 12f);
+ int x1 = (int) (x + 228 + (percentMove * 128));
+ RenderManager.drawRoundedRect(vg, x1, y + 2, 124, 28, OneConfigConfig.BLUE_600, 10f);
+ RenderManager.drawString(vg, left, x + 290 - RenderManager.getTextWidth(vg, left, 12f, Fonts.INTER_MEDIUM) / 2, y + 17, OneConfigConfig.WHITE_90, 12f, Fonts.INTER_MEDIUM);
+ RenderManager.drawString(vg, right, x + 418 - RenderManager.getTextWidth(vg, right, 12f, Fonts.INTER_MEDIUM) / 2, y + 17, OneConfigConfig.WHITE_90, 12f, Fonts.INTER_MEDIUM);
+
+ if (InputUtils.isAreaClicked(x + 226, y, 256, 32)) {
+ toggled = !toggled;
+ try {
+ set(toggled);
+ } catch (IllegalAccessException e) {
+ System.err.println("failed to write config value: class=" + this + " fieldWatching=" + field + " valueWrite=" + toggled);
+ e.printStackTrace();
+ }
+ }
+ percentMove = MathUtils.clamp(MathUtils.easeOut(percentMove, toggled ? 1f : 0f, 10));
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigPageButton.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigPageButton.java
new file mode 100644
index 0000000..81e1dd0
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigPageButton.java
@@ -0,0 +1,57 @@
+package cc.polyfrost.oneconfig.gui.elements.config;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.data.OptionPage;
+import cc.polyfrost.oneconfig.config.interfaces.BasicOption;
+import cc.polyfrost.oneconfig.gui.OneConfigGui;
+import cc.polyfrost.oneconfig.gui.pages.ModConfigPage;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+import cc.polyfrost.oneconfig.utils.ColorUtils;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.nanovg.NanoVG;
+
+import java.lang.reflect.Field;
+
+public class ConfigPageButton extends BasicOption {
+ public final OptionPage page;
+ public final String description;
+ private int backgroundColor = OneConfigConfig.GRAY_500;
+
+ public ConfigPageButton(Field field, String name, String description, OptionPage page) {
+ super(field, name, 2);
+ this.description = description;
+ this.page = page;
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ int height = description.equals("") ? 64 : 96;
+ boolean hovered = InputUtils.isAreaHovered(x - 2, y, 1024, height);
+ boolean clicked = InputUtils.isAreaClicked(x - 2, y, 1024, height);
+ backgroundColor = ColorUtils.smoothColor(backgroundColor, OneConfigConfig.GRAY_500, OneConfigConfig.GRAY_400, hovered, 100);
+
+ if (hovered && Mouse.isButtonDown(0)) NanoVG.nvgGlobalAlpha(vg, 0.8f);
+
+ RenderManager.drawRoundedRect(vg, x - 16, y, 1024, height, backgroundColor, 20);
+ RenderManager.drawString(vg, name, x + 10, y + 32, OneConfigConfig.WHITE_90, 24, Fonts.INTER_MEDIUM);
+ if (!description.equals(""))
+ RenderManager.drawString(vg, name, x + 10, y + 70, OneConfigConfig.WHITE_90, 14, Fonts.INTER_MEDIUM);
+ RenderManager.drawImage(vg, Images.CHEVRON_ARROW, x + 981f, y + (description.equals("") ? 20f : 36f), 13, 22);
+
+ if (clicked) OneConfigGui.INSTANCE.openPage(new ModConfigPage(page));
+ NanoVG.nvgGlobalAlpha(vg, 1f);
+ }
+
+ @Override
+ public int getHeight() {
+ return description.equals("") ? 64 : 96;
+ }
+
+ @Override
+ public boolean hasHalfSize() {
+ return false;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigSlider.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigSlider.java
new file mode 100644
index 0000000..69cb887
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigSlider.java
@@ -0,0 +1,184 @@
+package cc.polyfrost.oneconfig.gui.elements.config;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.interfaces.BasicOption;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+import cc.polyfrost.oneconfig.utils.ColorUtils;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import cc.polyfrost.oneconfig.utils.MathUtils;
+import cc.polyfrost.oneconfig.gui.elements.BasicElement;
+import cc.polyfrost.oneconfig.gui.elements.TextInputField;
+import org.lwjgl.input.Mouse;
+import org.lwjgl.nanovg.NanoVG;
+
+import java.lang.reflect.Field;
+
+public class ConfigSlider extends BasicOption {
+ private final BasicElement slideYBoi = new BasicElement(24, 24, false);
+ private final TextInputField inputField = new TextInputField(84, 24, "", false, false);
+ private final BasicElement upArrow = new BasicElement(12, 14, false);
+ private final BasicElement downArrow = new BasicElement(12, 14, false);
+ private final float min, max;
+ private int steps = 0;
+ private int colorTop, colorBottom;
+ private boolean isFloat = true;
+ private Float prevAsNum = null;
+ private final int step;
+
+ public ConfigSlider(Field field, String name, int size, float min, float max, int step) {
+ super(field, name, size);
+ this.min = min;
+ this.max = max;
+ this.step = step;
+ if (step > 0) {
+ steps = (int) ((max - min) / step);
+ }
+ slideYBoi.setCustomHitbox(28, 8);
+ inputField.onlyAcceptNumbers(true);
+ inputField.setCentered(true);
+ }
+
+ @Override
+ public int getHeight() {
+ return 32;
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ float value = 0;
+ try {
+ Object object = get();
+ if (object instanceof Integer)
+ isFloat = false;
+ if (isFloat) value = (float) object;
+ else value = (int) object;
+ if (prevAsNum == null) prevAsNum = value;
+ } catch (IllegalAccessException ignored) {
+ }
+ float current = MathUtils.clamp((value - min) / (max - min));
+
+ float currentAsNum = current * (max - min) + min;
+ if (!inputField.isToggled()) inputField.setInput(String.format("%.01f", currentAsNum));
+ inputField.setErrored(false);
+ if (inputField.isToggled()) {
+ try {
+ float input = Float.parseFloat(inputField.getInput());
+ if (input < min) {
+ inputField.setErrored(true);
+ input = min;
+ }
+ if (input > max) {
+ inputField.setErrored(true);
+ input = max;
+ }
+ if (steps == 0) {
+ current = MathUtils.clamp((input - min) / (max - min));
+ } else {
+ current = toNearestStep(MathUtils.clamp((input - min) / (max - min)));
+ }
+ } catch (NumberFormatException ignored) {
+ inputField.setErrored(true);
+ }
+ }
+ inputField.draw(vg, x + 892, y);
+
+ RenderManager.drawString(vg, name, x, y + 17, OneConfigConfig.WHITE_90, 14f, Fonts.INTER_MEDIUM);
+ RenderManager.drawRoundedRect(vg, x + 352, y + 13, 512, 6, OneConfigConfig.GRAY_300, 4f);
+ slideYBoi.update(x + 340 + (int) (current * 512), y + 4);
+ if (steps != 0) {
+ for (float i = 0; i <= 1.005f; i += 1f / steps) { // sometimes it's just more than 1, so we add a little
+ int color = current > i ? OneConfigConfig.BLUE_500 : OneConfigConfig.GRAY_300;
+ RenderManager.drawRoundedRect(vg, x + 351 + (int) (i * 512), y + 9, 4, 14, color, 2f);
+ }
+ }
+ RenderManager.drawRoundedRect(vg, x + 352, y + 13, (int) (current * 512), 6, OneConfigConfig.BLUE_500, 4f);
+ if (steps == 0)
+ RenderManager.drawRoundedRect(vg, x + 340 + (int) (current * 512), y + 4, 24, 24, OneConfigConfig.WHITE, 12f);
+ else
+ RenderManager.drawRoundedRect(vg, x + 346 + (int) (current * 512), y + 4, 8, 24, OneConfigConfig.WHITE, 4f);
+
+ int mouseX = InputUtils.mouseX() - (x + 352);
+ if (InputUtils.isAreaClicked(x + 332, y + 9, 542, 10) && !slideYBoi.isHovered()) {
+ if (steps == 0) {
+ current = MathUtils.clamp(mouseX / 512f);
+ } else current = MathUtils.clamp(toNearestStep(mouseX / 512f));
+ }
+ if (slideYBoi.isHovered() && Mouse.isButtonDown(0)) {
+ if (steps == 0) {
+ current = MathUtils.clamp(mouseX / 512f);
+ } else current = MathUtils.clamp(toNearestStep(mouseX / 512f));
+ }
+ currentAsNum = current * (max - min) + min;
+
+ RenderManager.drawRoundedRect(vg, x + 980, y, 12, 28, OneConfigConfig.GRAY_500, 6f);
+ upArrow.update(x + 980, y);
+ downArrow.update(x + 980, y + 14);
+ if (current == 1f) colorTop = OneConfigConfig.GRAY_500_80;
+ if (current == 0f) colorBottom = OneConfigConfig.GRAY_500_80;
+ colorTop = ColorUtils.getColor(colorTop, 2, upArrow.isHovered(), upArrow.isClicked());
+ colorBottom = ColorUtils.getColor(colorBottom, 2, downArrow.isHovered(), downArrow.isClicked());
+ if (upArrow.isClicked()) {
+ currentAsNum += step == 0 ? 1 : step;
+ current = MathUtils.clamp((currentAsNum - min) / (max - min));
+ }
+ if (downArrow.isClicked()) {
+ currentAsNum -= step == 0 ? 1 : step;
+ current = MathUtils.clamp((currentAsNum - min) / (max - min));
+ }
+ if (current == 1f) NanoVG.nvgGlobalAlpha(vg, 0.3f);
+ RenderManager.drawRoundedRectVaried(vg, x + 980, y, 12, 14, colorTop, 6f, 6f, 0f, 0f);
+ RenderManager.drawImage(vg, Images.UP_ARROW, x + 981, y + 2, 10, 10);
+ if (current == 1f) NanoVG.nvgGlobalAlpha(vg, 1f);
+
+ if (current == 0f) NanoVG.nvgGlobalAlpha(vg, 0.3f);
+ RenderManager.drawRoundedRectVaried(vg, x + 980, y + 14, 12, 14, colorBottom, 0f, 0f, 6f, 6f);
+ NanoVG.nvgTranslate(vg, x + 991, y + 25);
+ NanoVG.nvgRotate(vg, (float) Math.toRadians(180));
+ RenderManager.drawImage(vg, Images.UP_ARROW, 0, 0, 10, 10);
+ NanoVG.nvgResetTransform(vg);
+ NanoVG.nvgGlobalAlpha(vg, 1f);
+
+ if (currentAsNum != prevAsNum) {
+ try {
+ if (isFloat) set(currentAsNum);
+ else set(Math.round(currentAsNum));
+ } catch (IllegalAccessException ignored) {
+ }
+ prevAsNum = currentAsNum;
+ }
+ }
+
+ private float toNearestStep(float input) {
+ float stepF = 1f / steps;
+ float stepAbove = 1f, stepBelow = 0f;
+ for (float a = 0f; a <= 1f; a += stepF) {
+ if (a > input) {
+ stepAbove = a;
+ break;
+ }
+ }
+ for (float a = 1f; a >= 0f; a -= stepF) {
+ if (a <= input) {
+ stepBelow = a;
+ break;
+ }
+ }
+ if (stepAbove - input > input - stepBelow) {
+ return stepBelow;
+ } else {
+ return stepAbove;
+ }
+ }
+
+ @Override
+ public boolean hasHalfSize() {
+ return false;
+ }
+
+ @Override
+ public void keyTyped(char key, int keyCode) {
+ inputField.keyTyped(key, keyCode);
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigSwitch.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigSwitch.java
new file mode 100644
index 0000000..01e2f14
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigSwitch.java
@@ -0,0 +1,54 @@
+package cc.polyfrost.oneconfig.gui.elements.config;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.interfaces.BasicOption;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.utils.ColorUtils;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import cc.polyfrost.oneconfig.utils.MathUtils;
+
+import java.lang.reflect.Field;
+
+public class ConfigSwitch extends BasicOption {
+ private int color;
+ private float percentOn = 0f;
+
+ public ConfigSwitch(Field field, String name, int size) {
+ super(field, name, size);
+
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ boolean toggled = false;
+ try {
+ toggled = (boolean) get();
+ } catch (IllegalAccessException ignored) {
+ }
+ int x2 = x + 3 + (int) (percentOn * 18);
+ color = ColorUtils.smoothColor(color, OneConfigConfig.GRAY_400, OneConfigConfig.BLUE_500, toggled, 20f);
+ if (color == -15123643) {
+ color = OneConfigConfig.GRAY_400;
+ }
+ RenderManager.drawRoundedRect(vg, x, y + 4, 42, 24, color, 12f);
+ RenderManager.drawRoundedRect(vg, x2, y + 7, 18, 18, OneConfigConfig.WHITE, 9f);
+ RenderManager.drawString(vg, name, x + 50, y + 17, OneConfigConfig.WHITE, 14f, Fonts.INTER_MEDIUM);
+
+ if (InputUtils.isAreaClicked(x, y, 42, 32)) {
+ toggled = !toggled;
+ try {
+ set(toggled);
+ } catch (IllegalAccessException e) {
+ System.err.println("failed to write config value: class=" + this + " fieldWatching=" + field + " valueWrite=" + toggled);
+ e.printStackTrace();
+ }
+ }
+ percentOn = MathUtils.clamp(MathUtils.easeOut(percentOn, toggled ? 1f : 0f, 10));
+ }
+
+ @Override
+ public int getHeight() {
+ return 32;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigTextBox.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigTextBox.java
new file mode 100644
index 0000000..94ed127
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigTextBox.java
@@ -0,0 +1,61 @@
+package cc.polyfrost.oneconfig.gui.elements.config;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.interfaces.BasicOption;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import cc.polyfrost.oneconfig.gui.elements.TextInputField;
+
+import java.awt.*;
+import java.lang.reflect.Field;
+
+public class ConfigTextBox extends BasicOption {
+ private final boolean secure;
+ private final boolean multiLine;
+ private final TextInputField textField;
+
+ public ConfigTextBox(Field field, String name, int size, String placeholder, boolean secure, boolean multiLine) {
+ super(field, name, size);
+ this.secure = secure;
+ this.multiLine = multiLine;
+ this.textField = new TextInputField(size == 1 && hasHalfSize() ? 256 : 640, multiLine ? 64 : 32, placeholder, multiLine, secure);
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ RenderManager.drawString(vg, name, x, y + 16, OneConfigConfig.WHITE_90, 14, Fonts.INTER_MEDIUM);
+
+ try {
+ String value = (String) get();
+ textField.setInput(value == null ? "" : value);
+ } catch (IllegalAccessException ignored) {
+ }
+
+ textField.draw(vg, x + (size == 1 && hasHalfSize() ? 224 : 352), y);
+
+ if (secure)
+ RenderManager.drawImage(vg, Images.HIDE_EYE, x + 967, y + 7, 18, 18, new Color(196, 196, 196).getRGB());
+ if (secure && InputUtils.isAreaClicked(x + 967, y + 7, 18, 18)) textField.setPassword(!textField.getPassword());
+ }
+
+ @Override
+ public void keyTyped(char key, int keyCode) {
+ textField.keyTyped(key, keyCode);
+ try {
+ set(textField.getInput());
+ } catch (IllegalAccessException ignored) {
+ }
+ }
+
+ @Override
+ public int getHeight() {
+ return multiLine ? 64 : 32;
+ }
+
+ @Override
+ public boolean hasHalfSize() {
+ return !secure && !multiLine;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigUniSelector.java b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigUniSelector.java
new file mode 100644
index 0000000..0623f1e
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/elements/config/ConfigUniSelector.java
@@ -0,0 +1,78 @@
+package cc.polyfrost.oneconfig.gui.elements.config;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.interfaces.BasicOption;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.Scissor;
+import cc.polyfrost.oneconfig.lwjgl.ScissorManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+import cc.polyfrost.oneconfig.utils.InputUtils;
+import cc.polyfrost.oneconfig.utils.MathUtils;
+import org.lwjgl.nanovg.NanoVG;
+
+import java.lang.reflect.Field;
+
+public class ConfigUniSelector extends BasicOption {
+ private final String[] options;
+ private float percentMove = 1f;
+ private int previous = -1;
+
+ public ConfigUniSelector(Field field, String name, int size, String[] options) {
+ super(field, name, size);
+ this.options = options;
+ }
+
+ @Override
+ public int getHeight() {
+ return 32;
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ int selected = 0;
+ try {
+ selected = (int) get();
+ } catch (IllegalAccessException ignored) {
+ }
+ String option = options[selected] + " " + (selected + 1) + "/" + options.length;
+ RenderManager.drawString(vg, name, x, y + 16, OneConfigConfig.WHITE_90, 14f, Fonts.INTER_MEDIUM);
+
+ Scissor scissor = ScissorManager.scissor(vg, x + 256, y, 192, 32);
+ if (previous == -1) {
+ RenderManager.drawString(vg, option, x + 352 - RenderManager.getTextWidth(vg, option, 12f, Fonts.INTER_MEDIUM) / 2f, y + 15, OneConfigConfig.WHITE_90, 12f, Fonts.INTER_MEDIUM);
+ } else {
+ String prevOption = options[previous] + " " + (previous + 1) + "/" + options.length;
+ RenderManager.drawString(vg, selected < previous ? prevOption : option, x + 352 - RenderManager.getTextWidth(vg, selected < previous ? prevOption : option, 12f, Fonts.INTER_MEDIUM) / 2f + 192 * percentMove, y + 15, OneConfigConfig.WHITE_90, 12f, Fonts.INTER_MEDIUM);
+ RenderManager.drawString(vg, selected < previous ? option : prevOption, x + 352 - RenderManager.getTextWidth(vg, selected < previous ? option : prevOption, 12f, Fonts.INTER_MEDIUM) / 2f - 192 * (1 - percentMove), y + 15, OneConfigConfig.WHITE_90, 12f, Fonts.INTER_MEDIUM);
+ }
+ ScissorManager.resetScissor(vg, scissor);
+
+ // actual coordinates: 240, 7
+ NanoVG.nvgTranslate(vg, x + 248, y + 21);
+ NanoVG.nvgRotate(vg, (float) Math.toRadians(180));
+ RenderManager.drawImage(vg, Images.CHEVRON_ARROW, 0, 0, 8, 14, OneConfigConfig.BLUE_400);
+ NanoVG.nvgResetTransform(vg);
+ RenderManager.drawImage(vg, Images.CHEVRON_ARROW, x + 456, y + 7, 8, 14, OneConfigConfig.BLUE_400);
+
+ if (InputUtils.isAreaClicked(x + 235, y + 5, 18, 18) && selected > 0) {
+ previous = selected;
+ selected -= 1;
+ try {
+ set(selected);
+ } catch (IllegalAccessException ignored) {
+ }
+ percentMove = selected < previous ? 0f : 1f;
+ } else if (InputUtils.isAreaClicked(x + 451, y + 5, 18, 18) && selected < options.length - 1) {
+ previous = selected;
+ selected += 1;
+ try {
+ set(selected);
+ } catch (IllegalAccessException ignored) {
+ }
+ percentMove = selected < previous ? 0f : 1f;
+ }
+ if (previous != -1) percentMove = MathUtils.easeOut(percentMove, selected < previous ? 1f : 0f, 10);
+ if ((selected < previous ? 1f : 0f) == percentMove) previous = -1;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/pages/HomePage.java b/src/main/java/cc/polyfrost/oneconfig/gui/pages/HomePage.java
new file mode 100644
index 0000000..83e095c
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/pages/HomePage.java
@@ -0,0 +1,28 @@
+package cc.polyfrost.oneconfig.gui.pages;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.gui.elements.BasicButton;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.lwjgl.image.Images;
+
+public class HomePage extends Page {
+ private final BasicButton btn = new BasicButton(184, 36, "Socials", Images.SHARE, Images.LAUNCH, 1, BasicButton.ALIGNMENT_CENTER);
+
+ public HomePage() {
+ super("Home Dashboard");
+ }
+
+ public void draw(long vg, int x, int y) {
+ RenderManager.drawRoundedRect(vg, x, y, 184, 36, -1, 12f);
+ RenderManager.drawString(vg, "This is a cool string to test pages", x + 32, y + 72, -1, 36f, Fonts.INTER_BOLD);
+ RenderManager.drawRoundedRect(vg, x + 350, y + 310, 300, 200, OneConfigConfig.BLUE_600, 14f);
+ //RenderManager.drawRoundedRect(vg);
+ btn.draw(vg, x + 432, y + 658);
+ }
+
+ @Override
+ public boolean isBase() {
+ return true;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/pages/ModConfigPage.java b/src/main/java/cc/polyfrost/oneconfig/gui/pages/ModConfigPage.java
new file mode 100644
index 0000000..f335e4d
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/pages/ModConfigPage.java
@@ -0,0 +1,152 @@
+package cc.polyfrost.oneconfig.gui.pages;
+
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.data.OptionPage;
+import cc.polyfrost.oneconfig.config.interfaces.BasicOption;
+import cc.polyfrost.oneconfig.gui.elements.BasicButton;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.gui.elements.config.ConfigPageButton;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+
+import java.util.ArrayList;
+
+public class ModConfigPage extends Page {
+ private final OptionPage page;
+ private final ArrayList<BasicButton> categories = new ArrayList<>();
+ private String selectedCategory;
+
+ public ModConfigPage(OptionPage page) {
+ super(page.name);
+ this.page = page;
+ if (page.categories.size() == 0) return;
+ for (String category : page.categories.keySet()) {
+ selectedCategory = category;
+ break;
+ }
+ if (page.categories.size() < 2) return;
+ for (String category : page.categories.keySet()) {
+ BasicButton button = new BasicButton(0, 32, category, null, null, 0, BasicButton.ALIGNMENT_CENTER, true, () -> switchCategory(category));
+ if (category.equals(selectedCategory)) button.setToggled(true);
+ categories.add(button);
+ }
+ }
+
+ @Override
+ public void draw(long vg, int x, int y) {
+ if (page.categories.size() == 0) return;
+ int optionX = x + 30;
+ int optionY = y + (page.categories.size() == 1 ? 16 : 64);
+
+ // Category buttons
+ int buttonX = x + 16;
+ for (BasicButton button : categories) {
+ if (button.getWidth() == 0)
+ button.setWidth((int) (Math.ceil(RenderManager.getTextWidth(vg, button.getText(), 14f, Fonts.INTER_MEDIUM) / 8f) * 8 + 16));
+ button.draw(vg, buttonX, y + 16);
+ buttonX += button.getWidth() + 16;
+ }
+
+ // Top page buttons
+ for (ConfigPageButton page : page.categories.get(selectedCategory).topPages) {
+ page.draw(vg, optionX, optionY);
+ optionY += page.getHeight() + 16;
+ }
+
+ // Background
+ if (page.categories.get(selectedCategory).subcategories.keySet().size() > 0) {
+ int backgroundSize = 16;
+ for (String subCategory : page.categories.get(selectedCategory).subcategories.keySet()) {
+ backgroundSize += 48;
+ for (int i = 0; i < page.categories.get(selectedCategory).subcategories.get(subCategory).size(); i++) {
+ BasicOption option = page.categories.get(selectedCategory).subcategories.get(subCategory).get(i);
+ if (i + 1 < page.categories.get(selectedCategory).subcategories.get(subCategory).size()) {
+ BasicOption nextOption = page.categories.get(selectedCategory).subcategories.get(subCategory).get(i + 1);
+ if (option.size == 1 && option.hasHalfSize() && nextOption.size == 1 && nextOption.hasHalfSize()) {
+ backgroundSize += Math.max(option.getHeight(), nextOption.getHeight()) + 16;
+ i++;
+ continue;
+ }
+ }
+ backgroundSize += option.getHeight() + 16;
+ }
+ }
+ RenderManager.drawRoundedRect(vg, x + 14, optionY, 1024, backgroundSize, OneConfigConfig.GRAY_900, 20);
+ }
+
+ // draw options
+ int optionLastY = optionY + 16;
+ if (page.categories.get(selectedCategory).subcategories.keySet().size() > 0) {
+ optionY += 16;
+ for (String subCategory : page.categories.get(selectedCategory).subcategories.keySet()) {
+ RenderManager.drawString(vg, subCategory, optionX, optionY + 16, OneConfigConfig.WHITE_90, 24f, Fonts.INTER_MEDIUM);
+ optionY += 48;
+ for (int i = 0; i < page.categories.get(selectedCategory).subcategories.get(subCategory).size(); i++) {
+ BasicOption option = page.categories.get(selectedCategory).subcategories.get(subCategory).get(i);
+ option.draw(vg, optionX, optionY);
+ if (i + 1 < page.categories.get(selectedCategory).subcategories.get(subCategory).size()) {
+ BasicOption nextOption = page.categories.get(selectedCategory).subcategories.get(subCategory).get(i + 1);
+ if (option.size == 1 && option.hasHalfSize() && nextOption.size == 1 && nextOption.hasHalfSize()) {
+ nextOption.draw(vg, optionX + 512, optionY);
+ optionY += Math.max(option.getHeight(), nextOption.getHeight()) + 16;
+ i++;
+ continue;
+ }
+ }
+ optionY += option.getHeight() + 16;
+ }
+ }
+ optionY += 16;
+ }
+
+ // Bottom page buttons
+ for (ConfigPageButton page : page.categories.get(selectedCategory).bottomPages) {
+ page.draw(vg, optionX, optionY);
+ optionY += page.getHeight() + 16;
+ }
+
+ // Draw last options
+ if (page.categories.get(selectedCategory).subcategories.keySet().size() > 0) {
+ for (String subCategory : page.categories.get(selectedCategory).subcategories.keySet()) {
+ optionLastY += 48;
+ for (int i = 0; i < page.categories.get(selectedCategory).subcategories.get(subCategory).size(); i++) {
+ BasicOption option = page.categories.get(selectedCategory).subcategories.get(subCategory).get(i);
+ option.drawLast(vg, optionX, optionLastY);
+ if (i + 1 < page.categories.get(selectedCategory).subcategories.get(subCategory).size()) {
+ BasicOption nextOption = page.categories.get(selectedCategory).subcategories.get(subCategory).get(i + 1);
+ if (option.size == 1 && option.hasHalfSize() && nextOption.size == 1 && nextOption.hasHalfSize()) {
+ nextOption.drawLast(vg, optionX + 512, optionLastY);
+ optionLastY += Math.max(option.getHeight(), nextOption.getHeight()) + 16;
+ i++;
+ continue;
+ }
+ }
+ optionLastY += option.getHeight() + 16;
+ }
+ }
+ }
+ }
+
+ @Override
+ public void finishUpAndClose() {
+ page.mod.config.save();
+ }
+
+ @Override
+ public void keyTyped(char key, int keyCode) {
+ if (page.categories.size() == 0) return;
+ for (String subCategory : page.categories.get(selectedCategory).subcategories.keySet()) {
+ for (int i = 0; i < page.categories.get(selectedCategory).subcategories.get(subCategory).size(); i++) {
+ page.categories.get(selectedCategory).subcategories.get(subCategory).get(i).keyTyped(key, keyCode);
+ }
+ }
+ }
+
+ public void switchCategory(String newCategory) {
+ if (!page.categories.containsKey(newCategory)) return;
+ selectedCategory = newCategory;
+ for (BasicButton button : categories) {
+ if (button.getText().equals(newCategory)) continue;
+ button.setToggled(false);
+ }
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/pages/ModsPage.java b/src/main/java/cc/polyfrost/oneconfig/gui/pages/ModsPage.java
new file mode 100644
index 0000000..bb9cbd6
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/pages/ModsPage.java
@@ -0,0 +1,76 @@
+package cc.polyfrost.oneconfig.gui.pages;
+
+import cc.polyfrost.oneconfig.OneConfig;
+import cc.polyfrost.oneconfig.config.OneConfigConfig;
+import cc.polyfrost.oneconfig.config.data.Mod;
+import cc.polyfrost.oneconfig.config.data.ModType;
+import cc.polyfrost.oneconfig.gui.elements.BasicButton;
+import cc.polyfrost.oneconfig.lwjgl.font.Fonts;
+import cc.polyfrost.oneconfig.gui.elements.ModCard;
+import cc.polyfrost.oneconfig.lwjgl.RenderManager;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ModsPage extends Page {
+
+ private final List<ModCard> modCards = new ArrayList<>();
+ private final List<BasicButton> modCategories = new ArrayList<>();
+
+ public ModsPage() {
+ super("Mods");
+ for (Mod modData : OneConfig.loadedMods) {
+ modCards.add(new ModCard(modData, null, true, false, false));
+ }
+ for (ModCard card : modCards) {
+ if (card.isFavorite()) {
+ modCards.remove(card);
+ modCards.add(0, card);
+ }
+ }
+ modCategories.add(new BasicButton(64, 32, "All", null, null, 0, BasicButton.ALIGNMENT_CENTER, true, () -> unselect(0)));
+ modCategories.add(new BasicButton(80, 32, "Combat", null, null, 0, BasicButton.ALIGNMENT_CENTER, true, () -> unselect(1)));
+ modCategories.add(new BasicButton(64, 32, "HUD", null, null, 0, BasicButton.ALIGNMENT_CENTER, true, () -> unselect(2)));
+ modCategories.add(new BasicButton(104, 32, "Utility & QoL", null, null, 0, BasicButton.ALIGNMENT_CENTER, true, () -> unselect(3)));
+ modCategories.add(new BasicButton(80, 32, "Hypixel", null, null, 0, BasicButton.ALIGNMENT_CENTER, true, () -> unselect(4)));
+ modCategories.add(new BasicButton(80, 32, "Skyblock", null, null, 0, BasicButton.ALIGNMENT_CENTER, true, () -> unselect(5)));
+ modCategories.add(new BasicButton(88, 32, "3rd Party", null, null, 0, BasicButton.ALIGNMENT_CENTER, true, () -> unselect(6)));
+ modCategories.get(0).setToggled(true);
+ }
+
+ public void draw(long vg, int x, int y) {
+ int iXCat = x + 16;
+ for (BasicButton btn : modCategories) {
+ btn.draw(vg, iXCat, y + 16);
+ iXCat += btn.getWidth() + 8;
+ }
+
+ int iX = x + 16;
+ int iY = y + 72;
+ for (ModCard modCard : modCards) {
+ if (modCategories.get(0).isToggled() || (modCategories.get(1).isToggled() && modCard.getModData().modType == ModType.PVP) || (modCategories.get(2).isToggled() && modCard.getModData().modType == ModType.HUD) || (modCategories.get(3).isToggled() && modCard.getModData().modType == ModType.UTIL_QOL) || (modCategories.get(4).isToggled() && modCard.getModData().modType == ModType.HYPIXEL) || (modCategories.get(5).isToggled() && modCard.getModData().modType == ModType.SKYBLOCK) || (modCategories.get(6).isToggled() && modCard.getModData().modType == ModType.OTHER)) {
+ modCard.draw(vg, iX, iY);
+ iX += 260;
+ if (iX > x + 796) {
+ iX = x + 16;
+ iY += 135;
+ }
+ }
+ }
+ if (iX == x + 16 && iY == y + 72) {
+ RenderManager.drawString(vg, "Looks like there is nothing here. Try another category?", x + 16, y + 72, OneConfigConfig.WHITE_60, 14f, Fonts.INTER_MEDIUM);
+ }
+ }
+
+ private void unselect(int index) {
+ for (int i = 0; i < modCategories.size(); i++) {
+ if (index == i) continue;
+ modCategories.get(i).setToggled(false);
+ }
+ }
+
+ @Override
+ public boolean isBase() {
+ return true;
+ }
+}
diff --git a/src/main/java/cc/polyfrost/oneconfig/gui/pages/Page.java b/src/main/java/cc/polyfrost/oneconfig/gui/pages/Page.java
new file mode 100644
index 0000000..ba31fa8
--- /dev/null
+++ b/src/main/java/cc/polyfrost/oneconfig/gui/pages/Page.java
@@ -0,0 +1,31 @@
+package cc.polyfrost.oneconfig.gui.pages;
+
+/**
+ * A page is a 1056x728 rectangle of the GUI. It is the main content of the gui, and can be switched back and forwards easily. All the content of OneConfig is in a page.
+ */
+public abstract class Page {
+ protected final String title;
+
+ Page(String title) {
+ this.title = title;
+ }
+
+ public abstract void draw(long vg, int x, int y);
+
+ public void finishUpAndClose() {
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void keyTyped(char key, int keyCode) {
+ }
+
+ /**
+ * Overwrite this method and make it return true if you want this to always be the base in breadcrumbs
+ */
+ public boolean isBase() {
+ return false;
+ }
+}