From 3857800292a7cc078ee05c5487b11a256682bef1 Mon Sep 17 00:00:00 2001
From: nextdaydelivery <12willettsh@gmail.com>
Date: Sun, 13 Feb 2022 10:46:44 +0000
Subject: remake theme stuff + move packages around

---
 .../io/polyfrost/oneconfig/annotations/Button.java |  14 ---
 .../polyfrost/oneconfig/annotations/Category.java  |  13 --
 .../oneconfig/annotations/ColorPicker.java         |  14 ---
 .../polyfrost/oneconfig/annotations/Selector.java  |  15 ---
 .../io/polyfrost/oneconfig/annotations/Slider.java |  16 ---
 .../io/polyfrost/oneconfig/annotations/Switch.java |  13 --
 .../polyfrost/oneconfig/annotations/TextField.java |  15 ---
 .../oneconfig/config/annotations/Button.java       |  14 +++
 .../oneconfig/config/annotations/Category.java     |  13 ++
 .../oneconfig/config/annotations/ColorPicker.java  |  14 +++
 .../oneconfig/config/annotations/Selector.java     |  15 +++
 .../oneconfig/config/annotations/Slider.java       |  16 +++
 .../oneconfig/config/annotations/Switch.java       |  13 ++
 .../oneconfig/config/annotations/TextField.java    |  15 +++
 .../oneconfig/config/core/ConfigCore.java          |  11 ++
 .../polyfrost/oneconfig/config/data/ModData.java   |  24 ++++
 .../polyfrost/oneconfig/config/data/ModType.java   |  10 ++
 .../oneconfig/config/interfaces/Config.java        | 126 +++++++++++++++++++
 .../config/interfaces/OneConfigTypeAdapter.java    |  51 ++++++++
 .../interfaces/OneConfigTypeAdapterFactory.java    |  30 +++++
 .../oneconfig/config/interfaces/Option.java        |  76 ++++++++++++
 .../io/polyfrost/oneconfig/core/ConfigCore.java    |  11 --
 .../java/io/polyfrost/oneconfig/data/ModData.java  |  24 ----
 .../java/io/polyfrost/oneconfig/data/ModType.java  |  10 --
 .../java/io/polyfrost/oneconfig/gui/Window.java    |   5 +-
 .../gui/elements/config/OConfigButton.java         |   2 +-
 .../gui/elements/config/OConfigCategory.java       |   2 +-
 .../gui/elements/config/OConfigColor.java          |   2 +-
 .../gui/elements/config/OConfigSelector.java       |   2 +-
 .../gui/elements/config/OConfigSlider.java         |   2 +-
 .../gui/elements/config/OConfigSwitch.java         |   2 +-
 .../oneconfig/gui/elements/config/OConfigText.java |   2 +-
 .../io/polyfrost/oneconfig/interfaces/Config.java  | 126 -------------------
 .../oneconfig/interfaces/OneConfigTypeAdapter.java |  51 --------
 .../interfaces/OneConfigTypeAdapterFactory.java    |  30 -----
 .../io/polyfrost/oneconfig/interfaces/Option.java  |  76 ------------
 .../io/polyfrost/oneconfig/renderer/Renderer.java  |   3 +
 .../oneconfig/renderer/shaders/ShaderHelper.java   |   4 +
 .../io/polyfrost/oneconfig/test/TestConfig.java    |  12 +-
 .../polyfrost/oneconfig/themes/TextureManager.java |  82 +++++++++++++
 .../java/io/polyfrost/oneconfig/themes/Theme.java  | 136 ++-------------------
 .../polyfrost/oneconfig/themes/ThemeElement.java   |  42 +++++++
 .../java/io/polyfrost/oneconfig/themes/Themes.java |   1 +
 43 files changed, 584 insertions(+), 571 deletions(-)
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/annotations/Button.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/annotations/Category.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/annotations/ColorPicker.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/annotations/Selector.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/annotations/Slider.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/annotations/Switch.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/annotations/TextField.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/annotations/Button.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/annotations/Category.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/annotations/ColorPicker.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/annotations/Selector.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/annotations/Slider.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/annotations/Switch.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/annotations/TextField.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/core/ConfigCore.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/data/ModData.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/data/ModType.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/interfaces/Config.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/interfaces/OneConfigTypeAdapter.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/interfaces/OneConfigTypeAdapterFactory.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/config/interfaces/Option.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/core/ConfigCore.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/data/ModData.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/data/ModType.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/interfaces/Config.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/interfaces/OneConfigTypeAdapter.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/interfaces/OneConfigTypeAdapterFactory.java
 delete mode 100644 src/main/java/io/polyfrost/oneconfig/interfaces/Option.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/renderer/shaders/ShaderHelper.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/themes/TextureManager.java
 create mode 100644 src/main/java/io/polyfrost/oneconfig/themes/ThemeElement.java

(limited to 'src')

diff --git a/src/main/java/io/polyfrost/oneconfig/annotations/Button.java b/src/main/java/io/polyfrost/oneconfig/annotations/Button.java
deleted file mode 100644
index 98b735f..0000000
--- a/src/main/java/io/polyfrost/oneconfig/annotations/Button.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package io.polyfrost.oneconfig.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-public @interface Button {
-    String name();
-    String description() default "";
-    String text() default "Button";
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/annotations/Category.java b/src/main/java/io/polyfrost/oneconfig/annotations/Category.java
deleted file mode 100644
index 21c5533..0000000
--- a/src/main/java/io/polyfrost/oneconfig/annotations/Category.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package io.polyfrost.oneconfig.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.TYPE)
-public @interface Category {
-    String name();
-    String description() default "";
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/annotations/ColorPicker.java b/src/main/java/io/polyfrost/oneconfig/annotations/ColorPicker.java
deleted file mode 100644
index bf997a6..0000000
--- a/src/main/java/io/polyfrost/oneconfig/annotations/ColorPicker.java
+++ /dev/null
@@ -1,14 +0,0 @@
-package io.polyfrost.oneconfig.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-public @interface ColorPicker {
-    String name();
-    String description() default "";
-    boolean allowAlpha() default true;
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/annotations/Selector.java b/src/main/java/io/polyfrost/oneconfig/annotations/Selector.java
deleted file mode 100644
index 39d238c..0000000
--- a/src/main/java/io/polyfrost/oneconfig/annotations/Selector.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.polyfrost.oneconfig.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-public @interface Selector {
-    String name();
-    String description() default "";
-    String[] options();
-    int defaultSelection() default 0;
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/annotations/Slider.java b/src/main/java/io/polyfrost/oneconfig/annotations/Slider.java
deleted file mode 100644
index fa855bf..0000000
--- a/src/main/java/io/polyfrost/oneconfig/annotations/Slider.java
+++ /dev/null
@@ -1,16 +0,0 @@
-package io.polyfrost.oneconfig.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-public @interface Slider {
-    String name();
-    String description() default "";
-    float min();
-    float max();
-    float precision();
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/annotations/Switch.java b/src/main/java/io/polyfrost/oneconfig/annotations/Switch.java
deleted file mode 100644
index fffb490..0000000
--- a/src/main/java/io/polyfrost/oneconfig/annotations/Switch.java
+++ /dev/null
@@ -1,13 +0,0 @@
-package io.polyfrost.oneconfig.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-public @interface Switch {
-    String name();
-    String description() default "";
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/annotations/TextField.java b/src/main/java/io/polyfrost/oneconfig/annotations/TextField.java
deleted file mode 100644
index 5761dd6..0000000
--- a/src/main/java/io/polyfrost/oneconfig/annotations/TextField.java
+++ /dev/null
@@ -1,15 +0,0 @@
-package io.polyfrost.oneconfig.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-public @interface TextField {
-    String name();
-    String description() default "";
-    String placeholder() default "";
-    boolean hideText() default false;
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/annotations/Button.java b/src/main/java/io/polyfrost/oneconfig/config/annotations/Button.java
new file mode 100644
index 0000000..449d297
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/annotations/Button.java
@@ -0,0 +1,14 @@
+package io.polyfrost.oneconfig.config.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Button {
+    String name();
+    String description() default "";
+    String text() default "Button";
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/annotations/Category.java b/src/main/java/io/polyfrost/oneconfig/config/annotations/Category.java
new file mode 100644
index 0000000..05b5277
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/annotations/Category.java
@@ -0,0 +1,13 @@
+package io.polyfrost.oneconfig.config.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface Category {
+    String name();
+    String description() default "";
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/annotations/ColorPicker.java b/src/main/java/io/polyfrost/oneconfig/config/annotations/ColorPicker.java
new file mode 100644
index 0000000..feee4b4
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/annotations/ColorPicker.java
@@ -0,0 +1,14 @@
+package io.polyfrost.oneconfig.config.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface ColorPicker {
+    String name();
+    String description() default "";
+    boolean allowAlpha() default true;
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/annotations/Selector.java b/src/main/java/io/polyfrost/oneconfig/config/annotations/Selector.java
new file mode 100644
index 0000000..8b476ab
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/annotations/Selector.java
@@ -0,0 +1,15 @@
+package io.polyfrost.oneconfig.config.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Selector {
+    String name();
+    String description() default "";
+    String[] options();
+    int defaultSelection() default 0;
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/annotations/Slider.java b/src/main/java/io/polyfrost/oneconfig/config/annotations/Slider.java
new file mode 100644
index 0000000..cf8bfcd
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/annotations/Slider.java
@@ -0,0 +1,16 @@
+package io.polyfrost.oneconfig.config.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Slider {
+    String name();
+    String description() default "";
+    float min();
+    float max();
+    float precision();
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/annotations/Switch.java b/src/main/java/io/polyfrost/oneconfig/config/annotations/Switch.java
new file mode 100644
index 0000000..19ec1db
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/annotations/Switch.java
@@ -0,0 +1,13 @@
+package io.polyfrost.oneconfig.config.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Switch {
+    String name();
+    String description() default "";
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/annotations/TextField.java b/src/main/java/io/polyfrost/oneconfig/config/annotations/TextField.java
new file mode 100644
index 0000000..7b5837c
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/annotations/TextField.java
@@ -0,0 +1,15 @@
+package io.polyfrost.oneconfig.config.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface TextField {
+    String name();
+    String description() default "";
+    String placeholder() default "";
+    boolean hideText() default false;
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/core/ConfigCore.java b/src/main/java/io/polyfrost/oneconfig/config/core/ConfigCore.java
new file mode 100644
index 0000000..ff7ed28
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/core/ConfigCore.java
@@ -0,0 +1,11 @@
+package io.polyfrost.oneconfig.config.core;
+
+import io.polyfrost.oneconfig.config.data.ModData;
+import io.polyfrost.oneconfig.config.interfaces.Option;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class ConfigCore {
+    public static HashMap<ModData, ArrayList<Option>> settings = new HashMap<>();
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/data/ModData.java b/src/main/java/io/polyfrost/oneconfig/config/data/ModData.java
new file mode 100644
index 0000000..c5e6633
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/data/ModData.java
@@ -0,0 +1,24 @@
+package io.polyfrost.oneconfig.config.data;
+
+import io.polyfrost.oneconfig.config.interfaces.Config;
+
+public class ModData {
+    public final String name;
+    public final ModType modType;
+    public final String creator;
+    public final String version;
+    public Config config;
+
+    /**
+     * @param name    Friendly name of the mod
+     * @param modType Type of the mod (for example ModType.QOL)
+     * @param creator Creator of the mod
+     * @param version Version of the mod
+     */
+    public ModData(String name, ModType modType, String creator, String version) {
+        this.name = name;
+        this.modType = modType;
+        this.creator = creator;
+        this.version = version;
+    }
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/data/ModType.java b/src/main/java/io/polyfrost/oneconfig/config/data/ModType.java
new file mode 100644
index 0000000..8b6e7de
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/data/ModType.java
@@ -0,0 +1,10 @@
+package io.polyfrost.oneconfig.config.data;
+
+public enum ModType {
+    PVP,
+    PERFORMANCE,
+    HUD,
+    QOL,
+    HYPIXEL,
+    OTHER
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/interfaces/Config.java b/src/main/java/io/polyfrost/oneconfig/config/interfaces/Config.java
new file mode 100644
index 0000000..ce73f0c
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/interfaces/Config.java
@@ -0,0 +1,126 @@
+package io.polyfrost.oneconfig.config.interfaces;
+
+import com.google.gson.*;
+import io.polyfrost.oneconfig.config.annotations.*;
+import io.polyfrost.oneconfig.config.core.ConfigCore;
+import io.polyfrost.oneconfig.config.data.ModData;
+import io.polyfrost.oneconfig.gui.elements.config.*;
+
+import java.io.*;
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Map;
+
+public class Config {
+    private final File configFile;
+
+    Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).setPrettyPrinting()
+            .registerTypeAdapterFactory(OneConfigTypeAdapterFactory.getStaticTypeAdapterFactory()).create();
+
+    /**
+     * @param modData    information about the mod
+     * @param configFile file where config is stored
+     */
+    public Config(ModData modData, File configFile) {
+        this.configFile = configFile;
+        if (configFile.exists())
+            load();
+        else
+            save();
+        modData.config = this;
+        ConfigCore.settings.put(modData, generateOptionList(this.getClass()));
+    }
+
+    /**
+     * Save current config to file
+     */
+    public void save() {
+        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(configFile), StandardCharsets.UTF_8))) {
+            writer.write(gson.toJson(this.getClass()));
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Load file and overwrite current values
+     */
+    public void load() {
+        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8))) {
+            deserializePart(new JsonParser().parse(reader).getAsJsonObject(), this.getClass());
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Generate the option list for internal use only
+     *
+     * @param clazz target class
+     * @return list of options
+     */
+    private ArrayList<Option> generateOptionList(Class<?> clazz) {
+        ArrayList<Option> options = new ArrayList<>();
+        for (Class<?> innerClass : clazz.getClasses()) {
+            if (innerClass.isAnnotationPresent(Category.class)) {
+                Category category = innerClass.getAnnotation(Category.class);
+                options.add(new OConfigCategory(category.name(), category.description(), generateOptionList(innerClass)));
+            }
+        }
+        for (Field field : clazz.getFields()) {
+            if (field.isAnnotationPresent(Button.class)) {
+                Button button = field.getAnnotation(Button.class);
+                options.add(new OConfigButton(field, button.name(), button.description(), button.text()));
+            } else if (field.isAnnotationPresent(ColorPicker.class)) {
+                ColorPicker colorPicker = field.getAnnotation(ColorPicker.class);
+                options.add(new OConfigColor(field, colorPicker.name(), colorPicker.description(), colorPicker.allowAlpha()));
+            } else if (field.isAnnotationPresent(Selector.class)) {
+                Selector selector = field.getAnnotation(Selector.class);
+                options.add(new OConfigSelector(field, selector.name(), selector.description(), selector.options(), selector.defaultSelection()));
+            } else if (field.isAnnotationPresent(Slider.class)) {
+                Slider slider = field.getAnnotation(Slider.class);
+                options.add(new OConfigSlider(field, slider.name(), slider.description(), slider.min(), slider.max(), slider.precision()));
+            } else if (field.isAnnotationPresent(Switch.class)) {
+                Switch aSwitch = field.getAnnotation(Switch.class);
+                options.add(new OConfigSwitch(field, aSwitch.name(), aSwitch.description()));
+            } else if (field.isAnnotationPresent(TextField.class)) {
+                TextField textField = field.getAnnotation(TextField.class);
+                options.add(new OConfigText(field, textField.name(), textField.description(), textField.placeholder(), textField.hideText()));
+            }
+        }
+        return options;
+    }
+
+    /**
+     * Deserialize part of config and load values
+     *
+     * @param json  json to deserialize
+     * @param clazz target class
+     */
+    private void deserializePart(JsonObject json, Class<?> clazz) {
+        for (Map.Entry<String, JsonElement> element : json.entrySet()) {
+            String name = element.getKey();
+            JsonElement value = element.getValue();
+            if (value.isJsonObject()) {
+                for (Class<?> innerClass : clazz.getClasses()) {
+                    if (innerClass.getSimpleName().equals(name)) {
+                        deserializePart(value.getAsJsonObject(), innerClass);
+                        break;
+                    }
+                }
+            } else {
+                try {
+                    Field field = clazz.getField(name);
+                    TypeAdapter<?> adapter = gson.getAdapter(field.getType());
+                    Object object = adapter.fromJsonTree(value);
+                    field.setAccessible(true);
+                    field.set(null, object);
+                } catch (NoSuchFieldException | IllegalAccessException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/interfaces/OneConfigTypeAdapter.java b/src/main/java/io/polyfrost/oneconfig/config/interfaces/OneConfigTypeAdapter.java
new file mode 100644
index 0000000..a07e7c8
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/interfaces/OneConfigTypeAdapter.java
@@ -0,0 +1,51 @@
+package io.polyfrost.oneconfig.config.interfaces;
+
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonWriter;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+
+final class OneConfigTypeAdapter<T> extends TypeAdapter<Class<T>> {
+
+    private final Gson gson;
+    private final JsonParser parser = new JsonParser();
+
+    private OneConfigTypeAdapter(final Gson gson) {
+        this.gson = gson;
+    }
+
+    static <T> TypeAdapter<Class<T>> getStaticTypeAdapter(final Gson gson) {
+        return new OneConfigTypeAdapter<>(gson);
+    }
+
+    @Override
+    public void write(final JsonWriter out, final Class<T> value) throws IOException {
+        try {
+            out.beginObject();
+            for (Field field : value.getFields()) {
+                out.name(field.getName());
+                field.setAccessible(true);
+                final TypeAdapter<Object> adapter = (TypeAdapter) gson.getAdapter(field.getType());
+                adapter.write(out, field.get(null));
+            }
+            for (Class<?> clazz : value.getClasses()) {
+                out.name(clazz.getSimpleName());
+                final TypeAdapter<JsonElement> adapter = gson.getAdapter(JsonElement.class);
+                adapter.write(out, parser.parse(gson.toJson(clazz)));
+            }
+            out.endObject();
+        } catch (final IllegalAccessException ex) {
+            throw new IOException(ex);
+        }
+    }
+
+    @Override
+    public Class<T> read(final JsonReader in) throws IOException {
+        return null;
+    }
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/interfaces/OneConfigTypeAdapterFactory.java b/src/main/java/io/polyfrost/oneconfig/config/interfaces/OneConfigTypeAdapterFactory.java
new file mode 100644
index 0000000..af57163
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/interfaces/OneConfigTypeAdapterFactory.java
@@ -0,0 +1,30 @@
+package io.polyfrost.oneconfig.config.interfaces;
+
+import com.google.gson.Gson;
+import com.google.gson.TypeAdapter;
+import com.google.gson.TypeAdapterFactory;
+import com.google.gson.reflect.TypeToken;
+
+import java.lang.reflect.Type;
+
+import static io.polyfrost.oneconfig.config.interfaces.OneConfigTypeAdapter.getStaticTypeAdapter;
+
+public class OneConfigTypeAdapterFactory implements TypeAdapterFactory {
+
+    private static final TypeAdapterFactory staticTypeAdapterFactory = new OneConfigTypeAdapterFactory();
+
+    public static TypeAdapterFactory getStaticTypeAdapterFactory() {
+        return staticTypeAdapterFactory;
+    }
+
+    @Override
+    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
+        final Type type = typeToken.getType();
+        if (type.equals(Class.class)) {
+            @SuppressWarnings("unchecked") final TypeAdapter<T> castStaticTypeAdapter = (TypeAdapter<T>) getStaticTypeAdapter(gson);
+            return castStaticTypeAdapter;
+        }
+        return null;
+    }
+
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/config/interfaces/Option.java b/src/main/java/io/polyfrost/oneconfig/config/interfaces/Option.java
new file mode 100644
index 0000000..5980a63
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/config/interfaces/Option.java
@@ -0,0 +1,76 @@
+package io.polyfrost.oneconfig.config.interfaces;
+
+import java.lang.reflect.Field;
+
+@SuppressWarnings({"unused"})
+public abstract class Option {
+    protected final Field field;
+    protected final String name;
+    protected final String description;
+
+    /**
+     * Initialize option
+     *
+     * @param field       variable attached to option (null for category)
+     * @param name        name of option
+     * @param description description of option
+     */
+    public Option(Field field, String name, String description) {
+        this.field = field;
+        this.name = name;
+        this.description = description;
+        if (field != null)
+            field.setAccessible(true);
+    }
+
+    /**
+     * @param object Java object to set the variable to
+     */
+    protected void set(Object object) throws IllegalAccessException {
+        if (field == null) return;
+        field.set(null, object);
+    }
+
+    /**
+     * @return value of variable as Java object
+     */
+    protected Object get() throws IllegalAccessException {
+        if (field == null) return null;
+        return field.get(null);
+    }
+
+    /**
+     * @return height of option to align other options accordingly
+     */
+    public abstract int getHeight();
+
+    /**
+     * Function that gets called when drawing option
+     *
+     * @param x      x position
+     * @param y      y position
+     * @param width  width of menu
+     * @param mouseX x position of mouse
+     * @param mouseY y position of mouse
+     */
+    public abstract void draw(int x, int y, int width, int mouseX, int mouseY);
+
+    /**
+     * Function that gets called when mouse is clicked
+     *
+     * @param mouseX      x position of mouse
+     * @param mouseY      y position of mouse
+     * @param mouseButton button that got pressed
+     */
+    protected void onMouseClicked(int mouseX, int mouseY, int mouseButton) {
+    }
+
+    /**
+     * Function that gets called when a key is typed
+     *
+     * @param typedChar char that has been typed
+     * @param keyCode   code of key
+     */
+    protected void keyTyped(char typedChar, int keyCode) {
+    }
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/core/ConfigCore.java b/src/main/java/io/polyfrost/oneconfig/core/ConfigCore.java
deleted file mode 100644
index 8fe7c81..0000000
--- a/src/main/java/io/polyfrost/oneconfig/core/ConfigCore.java
+++ /dev/null
@@ -1,11 +0,0 @@
-package io.polyfrost.oneconfig.core;
-
-import io.polyfrost.oneconfig.data.ModData;
-import io.polyfrost.oneconfig.interfaces.Option;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-
-public class ConfigCore {
-    public static HashMap<ModData, ArrayList<Option>> settings = new HashMap<>();
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/data/ModData.java b/src/main/java/io/polyfrost/oneconfig/data/ModData.java
deleted file mode 100644
index 24ed1e5..0000000
--- a/src/main/java/io/polyfrost/oneconfig/data/ModData.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package io.polyfrost.oneconfig.data;
-
-import io.polyfrost.oneconfig.interfaces.Config;
-
-public class ModData {
-    public final String name;
-    public final ModType modType;
-    public final String creator;
-    public final String version;
-    public Config config;
-
-    /**
-     * @param name    Friendly name of the mod
-     * @param modType Type of the mod (for example ModType.QOL)
-     * @param creator Creator of the mod
-     * @param version Version of the mod
-     */
-    public ModData(String name, ModType modType, String creator, String version) {
-        this.name = name;
-        this.modType = modType;
-        this.creator = creator;
-        this.version = version;
-    }
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/data/ModType.java b/src/main/java/io/polyfrost/oneconfig/data/ModType.java
deleted file mode 100644
index 18cf638..0000000
--- a/src/main/java/io/polyfrost/oneconfig/data/ModType.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package io.polyfrost.oneconfig.data;
-
-public enum ModType {
-    PVP,
-    PERFORMANCE,
-    HUD,
-    QOL,
-    HYPIXEL,
-    OTHER
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/gui/Window.java b/src/main/java/io/polyfrost/oneconfig/gui/Window.java
index 5ef880b..a0c15cb 100644
--- a/src/main/java/io/polyfrost/oneconfig/gui/Window.java
+++ b/src/main/java/io/polyfrost/oneconfig/gui/Window.java
@@ -1,7 +1,7 @@
 package io.polyfrost.oneconfig.gui;
 
-import io.polyfrost.oneconfig.renderer.Renderer;
 import io.polyfrost.oneconfig.themes.Theme;
+import io.polyfrost.oneconfig.themes.ThemeElement;
 import io.polyfrost.oneconfig.themes.Themes;
 import net.minecraft.client.gui.Gui;
 import net.minecraft.client.gui.GuiScreen;
@@ -49,8 +49,7 @@ public class Window extends GuiScreen {
         Gui.drawRect(left, top, right, top + 100, t.getTitleBarColor().getRGB());
         Gui.drawRect(left, top + 100, right, top + 101, testingColor.getRGB());
 
-        //ResourceLocation location = mc.getRenderManager().renderEngine.getDynamicTextureLocation("oneconfig",new DynamicTexture(ImageIO.read(t.getResource("assets/textures/icons/hudsettings128.png"))));
-        Renderer.drawScaledImage(t.getLargeIconAtlas(), left + 10, top + 10, 128, 1152);
+        t.getTextureManager().draw(ThemeElement.ALL_MODS, 10, 10, 32, 32);
     }
 
     public static Window getWindow() {
diff --git a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigButton.java b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigButton.java
index a6951a6..1cf0ab8 100644
--- a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigButton.java
+++ b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigButton.java
@@ -1,6 +1,6 @@
 package io.polyfrost.oneconfig.gui.elements.config;
 
-import io.polyfrost.oneconfig.interfaces.Option;
+import io.polyfrost.oneconfig.config.interfaces.Option;
 
 import java.lang.reflect.Field;
 
diff --git a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigCategory.java b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigCategory.java
index 0eae75a..e57f130 100644
--- a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigCategory.java
+++ b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigCategory.java
@@ -1,6 +1,6 @@
 package io.polyfrost.oneconfig.gui.elements.config;
 
-import io.polyfrost.oneconfig.interfaces.Option;
+import io.polyfrost.oneconfig.config.interfaces.Option;
 
 import java.util.List;
 
diff --git a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigColor.java b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigColor.java
index fb60af7..fcad08f 100644
--- a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigColor.java
+++ b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigColor.java
@@ -1,6 +1,6 @@
 package io.polyfrost.oneconfig.gui.elements.config;
 
-import io.polyfrost.oneconfig.interfaces.Option;
+import io.polyfrost.oneconfig.config.interfaces.Option;
 
 import java.lang.reflect.Field;
 
diff --git a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSelector.java b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSelector.java
index c979131..3e0e208 100644
--- a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSelector.java
+++ b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSelector.java
@@ -1,6 +1,6 @@
 package io.polyfrost.oneconfig.gui.elements.config;
 
-import io.polyfrost.oneconfig.interfaces.Option;
+import io.polyfrost.oneconfig.config.interfaces.Option;
 
 import java.lang.reflect.Field;
 
diff --git a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSlider.java b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSlider.java
index 55c1222..0427b35 100644
--- a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSlider.java
+++ b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSlider.java
@@ -1,6 +1,6 @@
 package io.polyfrost.oneconfig.gui.elements.config;
 
-import io.polyfrost.oneconfig.interfaces.Option;
+import io.polyfrost.oneconfig.config.interfaces.Option;
 
 import java.lang.reflect.Field;
 
diff --git a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSwitch.java b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSwitch.java
index 1fa1590..08c315f 100644
--- a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSwitch.java
+++ b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigSwitch.java
@@ -1,6 +1,6 @@
 package io.polyfrost.oneconfig.gui.elements.config;
 
-import io.polyfrost.oneconfig.interfaces.Option;
+import io.polyfrost.oneconfig.config.interfaces.Option;
 
 import java.lang.reflect.Field;
 
diff --git a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigText.java b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigText.java
index 195607a..407f733 100644
--- a/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigText.java
+++ b/src/main/java/io/polyfrost/oneconfig/gui/elements/config/OConfigText.java
@@ -1,6 +1,6 @@
 package io.polyfrost.oneconfig.gui.elements.config;
 
-import io.polyfrost.oneconfig.interfaces.Option;
+import io.polyfrost.oneconfig.config.interfaces.Option;
 
 import java.lang.reflect.Field;
 
diff --git a/src/main/java/io/polyfrost/oneconfig/interfaces/Config.java b/src/main/java/io/polyfrost/oneconfig/interfaces/Config.java
deleted file mode 100644
index 3549456..0000000
--- a/src/main/java/io/polyfrost/oneconfig/interfaces/Config.java
+++ /dev/null
@@ -1,126 +0,0 @@
-package io.polyfrost.oneconfig.interfaces;
-
-import com.google.gson.*;
-import io.polyfrost.oneconfig.annotations.*;
-import io.polyfrost.oneconfig.core.ConfigCore;
-import io.polyfrost.oneconfig.data.ModData;
-import io.polyfrost.oneconfig.gui.elements.config.*;
-
-import java.io.*;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Map;
-
-public class Config {
-    private final File configFile;
-
-    Gson gson = new GsonBuilder().excludeFieldsWithModifiers(Modifier.TRANSIENT).setPrettyPrinting()
-            .registerTypeAdapterFactory(OneConfigTypeAdapterFactory.getStaticTypeAdapterFactory()).create();
-
-    /**
-     * @param modData    information about the mod
-     * @param configFile file where config is stored
-     */
-    public Config(ModData modData, File configFile) {
-        this.configFile = configFile;
-        if (configFile.exists())
-            load();
-        else
-            save();
-        modData.config = this;
-        ConfigCore.settings.put(modData, generateOptionList(this.getClass()));
-    }
-
-    /**
-     * Save current config to file
-     */
-    public void save() {
-        try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(configFile), StandardCharsets.UTF_8))) {
-            writer.write(gson.toJson(this.getClass()));
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * Load file and overwrite current values
-     */
-    public void load() {
-        try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(configFile), StandardCharsets.UTF_8))) {
-            deserializePart(new JsonParser().parse(reader).getAsJsonObject(), this.getClass());
-        } catch (IOException e) {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * Generate the option list for internal use only
-     *
-     * @param clazz target class
-     * @return list of options
-     */
-    private ArrayList<Option> generateOptionList(Class<?> clazz) {
-        ArrayList<Option> options = new ArrayList<>();
-        for (Class<?> innerClass : clazz.getClasses()) {
-            if (innerClass.isAnnotationPresent(Category.class)) {
-                Category category = innerClass.getAnnotation(Category.class);
-                options.add(new OConfigCategory(category.name(), category.description(), generateOptionList(innerClass)));
-            }
-        }
-        for (Field field : clazz.getFields()) {
-            if (field.isAnnotationPresent(Button.class)) {
-                Button button = field.getAnnotation(Button.class);
-                options.add(new OConfigButton(field, button.name(), button.description(), button.text()));
-            } else if (field.isAnnotationPresent(ColorPicker.class)) {
-                ColorPicker colorPicker = field.getAnnotation(ColorPicker.class);
-                options.add(new OConfigColor(field, colorPicker.name(), colorPicker.description(), colorPicker.allowAlpha()));
-            } else if (field.isAnnotationPresent(Selector.class)) {
-                Selector selector = field.getAnnotation(Selector.class);
-                options.add(new OConfigSelector(field, selector.name(), selector.description(), selector.options(), selector.defaultSelection()));
-            } else if (field.isAnnotationPresent(Slider.class)) {
-                Slider slider = field.getAnnotation(Slider.class);
-                options.add(new OConfigSlider(field, slider.name(), slider.description(), slider.min(), slider.max(), slider.precision()));
-            } else if (field.isAnnotationPresent(Switch.class)) {
-                Switch aSwitch = field.getAnnotation(Switch.class);
-                options.add(new OConfigSwitch(field, aSwitch.name(), aSwitch.description()));
-            } else if (field.isAnnotationPresent(TextField.class)) {
-                TextField textField = field.getAnnotation(TextField.class);
-                options.add(new OConfigText(field, textField.name(), textField.description(), textField.placeholder(), textField.hideText()));
-            }
-        }
-        return options;
-    }
-
-    /**
-     * Deserialize part of config and load values
-     *
-     * @param json  json to deserialize
-     * @param clazz target class
-     */
-    private void deserializePart(JsonObject json, Class<?> clazz) {
-        for (Map.Entry<String, JsonElement> element : json.entrySet()) {
-            String name = element.getKey();
-            JsonElement value = element.getValue();
-            if (value.isJsonObject()) {
-                for (Class<?> innerClass : clazz.getClasses()) {
-                    if (innerClass.getSimpleName().equals(name)) {
-                        deserializePart(value.getAsJsonObject(), innerClass);
-                        break;
-                    }
-                }
-            } else {
-                try {
-                    Field field = clazz.getField(name);
-                    TypeAdapter<?> adapter = gson.getAdapter(field.getType());
-                    Object object = adapter.fromJsonTree(value);
-                    field.setAccessible(true);
-                    field.set(null, object);
-                } catch (NoSuchFieldException | IllegalAccessException e) {
-                    e.printStackTrace();
-                }
-            }
-        }
-    }
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/interfaces/OneConfigTypeAdapter.java b/src/main/java/io/polyfrost/oneconfig/interfaces/OneConfigTypeAdapter.java
deleted file mode 100644
index df6ee87..0000000
--- a/src/main/java/io/polyfrost/oneconfig/interfaces/OneConfigTypeAdapter.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package io.polyfrost.oneconfig.interfaces;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonParser;
-import com.google.gson.TypeAdapter;
-import com.google.gson.stream.JsonReader;
-import com.google.gson.stream.JsonWriter;
-
-import java.io.IOException;
-import java.lang.reflect.Field;
-
-final class OneConfigTypeAdapter<T> extends TypeAdapter<Class<T>> {
-
-    private final Gson gson;
-    private final JsonParser parser = new JsonParser();
-
-    private OneConfigTypeAdapter(final Gson gson) {
-        this.gson = gson;
-    }
-
-    static <T> TypeAdapter<Class<T>> getStaticTypeAdapter(final Gson gson) {
-        return new OneConfigTypeAdapter<>(gson);
-    }
-
-    @Override
-    public void write(final JsonWriter out, final Class<T> value) throws IOException {
-        try {
-            out.beginObject();
-            for (Field field : value.getFields()) {
-                out.name(field.getName());
-                field.setAccessible(true);
-                final TypeAdapter<Object> adapter = (TypeAdapter) gson.getAdapter(field.getType());
-                adapter.write(out, field.get(null));
-            }
-            for (Class<?> clazz : value.getClasses()) {
-                out.name(clazz.getSimpleName());
-                final TypeAdapter<JsonElement> adapter = gson.getAdapter(JsonElement.class);
-                adapter.write(out, parser.parse(gson.toJson(clazz)));
-            }
-            out.endObject();
-        } catch (final IllegalAccessException ex) {
-            throw new IOException(ex);
-        }
-    }
-
-    @Override
-    public Class<T> read(final JsonReader in) throws IOException {
-        return null;
-    }
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/interfaces/OneConfigTypeAdapterFactory.java b/src/main/java/io/polyfrost/oneconfig/interfaces/OneConfigTypeAdapterFactory.java
deleted file mode 100644
index 6491ba2..0000000
--- a/src/main/java/io/polyfrost/oneconfig/interfaces/OneConfigTypeAdapterFactory.java
+++ /dev/null
@@ -1,30 +0,0 @@
-package io.polyfrost.oneconfig.interfaces;
-
-import com.google.gson.Gson;
-import com.google.gson.TypeAdapter;
-import com.google.gson.TypeAdapterFactory;
-import com.google.gson.reflect.TypeToken;
-
-import java.lang.reflect.Type;
-
-import static io.polyfrost.oneconfig.interfaces.OneConfigTypeAdapter.getStaticTypeAdapter;
-
-public class OneConfigTypeAdapterFactory implements TypeAdapterFactory {
-
-    private static final TypeAdapterFactory staticTypeAdapterFactory = new OneConfigTypeAdapterFactory();
-
-    public static TypeAdapterFactory getStaticTypeAdapterFactory() {
-        return staticTypeAdapterFactory;
-    }
-
-    @Override
-    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
-        final Type type = typeToken.getType();
-        if (type.equals(Class.class)) {
-            @SuppressWarnings("unchecked") final TypeAdapter<T> castStaticTypeAdapter = (TypeAdapter<T>) getStaticTypeAdapter(gson);
-            return castStaticTypeAdapter;
-        }
-        return null;
-    }
-
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/interfaces/Option.java b/src/main/java/io/polyfrost/oneconfig/interfaces/Option.java
deleted file mode 100644
index d996b60..0000000
--- a/src/main/java/io/polyfrost/oneconfig/interfaces/Option.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package io.polyfrost.oneconfig.interfaces;
-
-import java.lang.reflect.Field;
-
-@SuppressWarnings({"unused"})
-public abstract class Option {
-    protected final Field field;
-    protected final String name;
-    protected final String description;
-
-    /**
-     * Initialize option
-     *
-     * @param field       variable attached to option (null for category)
-     * @param name        name of option
-     * @param description description of option
-     */
-    public Option(Field field, String name, String description) {
-        this.field = field;
-        this.name = name;
-        this.description = description;
-        if (field != null)
-            field.setAccessible(true);
-    }
-
-    /**
-     * @param object Java object to set the variable to
-     */
-    protected void set(Object object) throws IllegalAccessException {
-        if (field == null) return;
-        field.set(null, object);
-    }
-
-    /**
-     * @return value of variable as Java object
-     */
-    protected Object get() throws IllegalAccessException {
-        if (field == null) return null;
-        return field.get(null);
-    }
-
-    /**
-     * @return height of option to align other options accordingly
-     */
-    public abstract int getHeight();
-
-    /**
-     * Function that gets called when drawing option
-     *
-     * @param x      x position
-     * @param y      y position
-     * @param width  width of menu
-     * @param mouseX x position of mouse
-     * @param mouseY y position of mouse
-     */
-    public abstract void draw(int x, int y, int width, int mouseX, int mouseY);
-
-    /**
-     * Function that gets called when mouse is clicked
-     *
-     * @param mouseX      x position of mouse
-     * @param mouseY      y position of mouse
-     * @param mouseButton button that got pressed
-     */
-    protected void onMouseClicked(int mouseX, int mouseY, int mouseButton) {
-    }
-
-    /**
-     * Function that gets called when a key is typed
-     *
-     * @param typedChar char that has been typed
-     * @param keyCode   code of key
-     */
-    protected void keyTyped(char typedChar, int keyCode) {
-    }
-}
diff --git a/src/main/java/io/polyfrost/oneconfig/renderer/Renderer.java b/src/main/java/io/polyfrost/oneconfig/renderer/Renderer.java
index f8612b7..313a1d0 100644
--- a/src/main/java/io/polyfrost/oneconfig/renderer/Renderer.java
+++ b/src/main/java/io/polyfrost/oneconfig/renderer/Renderer.java
@@ -5,10 +5,13 @@ import net.minecraft.client.gui.FontRenderer;
 import net.minecraft.client.gui.Gui;
 import net.minecraft.client.renderer.GlStateManager;
 import net.minecraft.util.ResourceLocation;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 import java.awt.*;
 
 public class Renderer extends Gui {
+    public static final Logger renderLog = LogManager.getLogger("OneConfig Renderer");
     private static final Minecraft mc = Minecraft.getMinecraft();
     private static final FontRenderer fr = mc.fontRendererObj;
 
diff --git a/src/main/java/io/polyfrost/oneconfig/renderer/shaders/ShaderHelper.java b/src/main/java/io/polyfrost/oneconfig/renderer/shaders/ShaderHelper.java
new file mode 100644
index 0000000..892719e
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/renderer/shaders/ShaderHelper.java
@@ -0,0 +1,4 @@
+package io.polyfrost.oneconfig.renderer.shaders;
+
+public class ShaderHelper {
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/test/TestConfig.java b/src/main/java/io/polyfrost/oneconfig/test/TestConfig.java
index 3cfceaa..04c912e 100644
--- a/src/main/java/io/polyfrost/oneconfig/test/TestConfig.java
+++ b/src/main/java/io/polyfrost/oneconfig/test/TestConfig.java
@@ -1,11 +1,11 @@
 package io.polyfrost.oneconfig.test;
 
-import io.polyfrost.oneconfig.annotations.Category;
-import io.polyfrost.oneconfig.annotations.Switch;
-import io.polyfrost.oneconfig.annotations.TextField;
-import io.polyfrost.oneconfig.data.ModData;
-import io.polyfrost.oneconfig.data.ModType;
-import io.polyfrost.oneconfig.interfaces.Config;
+import io.polyfrost.oneconfig.config.annotations.Category;
+import io.polyfrost.oneconfig.config.annotations.Switch;
+import io.polyfrost.oneconfig.config.annotations.TextField;
+import io.polyfrost.oneconfig.config.data.ModData;
+import io.polyfrost.oneconfig.config.data.ModType;
+import io.polyfrost.oneconfig.config.interfaces.Config;
 
 import java.io.File;
 
diff --git a/src/main/java/io/polyfrost/oneconfig/themes/TextureManager.java b/src/main/java/io/polyfrost/oneconfig/themes/TextureManager.java
new file mode 100644
index 0000000..749dea6
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/themes/TextureManager.java
@@ -0,0 +1,82 @@
+package io.polyfrost.oneconfig.themes;
+
+import javafx.util.Pair;
+import net.minecraft.client.Minecraft;
+import net.minecraft.client.gui.Gui;
+import net.minecraft.client.renderer.GlStateManager;
+import net.minecraft.client.renderer.texture.DynamicTexture;
+import net.minecraft.util.ResourceLocation;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.List;
+
+import static io.polyfrost.oneconfig.themes.Themes.themeLog;
+
+public class TextureManager {
+    private static final Minecraft mc = Minecraft.getMinecraft();
+    private final List<ResourceLocation> resources = new ArrayList<>();
+    private final List<ThemeElement> tickableTextureLocations = new ArrayList<>();
+    private final List<Pair<Integer, Integer>> tickableTextures = new ArrayList<>();
+    private int tick = 0;
+
+    /**
+     * Create a new texture manager for this theme, used for drawing of icons, etc.
+     */
+    public TextureManager(Theme theme) {
+        for(ThemeElement element : ThemeElement.values()) {
+            BufferedImage img;
+            try {
+                img = ImageIO.read(theme.getResource(element.location));
+            } catch (Exception e) {
+                themeLog.error("failed to get themed texture: " + element.location + ", having to fallback to default one. Is pack invalid?");
+                img = new BufferedImage(128,128,BufferedImage.TYPE_INT_ARGB);
+                // TODO add fallback
+            }
+            ResourceLocation location = mc.getTextureManager().getDynamicTextureLocation(element.location, new DynamicTexture(img));
+            resources.add(location);
+            if(img.getWidth() != element.size) {
+                themeLog.warn("Theme element " + element.name() + " with size " + img.getWidth() + "px is not recommended, expected " + element.size + "px. Continuing anyway.");
+            }
+            if(img.getWidth() != img.getHeight()) {
+                themeLog.info("found tickable animated texture (" + element.name() + "). Loading texture");
+                tickableTextureLocations.add(element);
+                tickableTextures.add(new Pair<>(img.getWidth(), img.getHeight()));
+            }
+        }
+    }
+
+    /**
+     * Draw the specified icon at the coordinates, scaled to the width and height.
+     * @param element element to draw
+     * @param x x coordinate (top left)
+     * @param y y coordinate (top left)
+     * @param width width of the image
+     * @param height height of the image
+     */
+    public void draw(ThemeElement element, int x, int y, int width, int height) {
+        GlStateManager.enableBlend();
+        GlStateManager.color(1f, 1f, 1f, 1f);
+        ResourceLocation location = resources.get(element.ordinal());
+        mc.getTextureManager().bindTexture(location);
+        try {
+            if(tickableTextureLocations.contains(element)) {
+                int texWidth = tickableTextures.get(0).getKey();        // TODO unsure if this works safe
+                int texHeight = tickableTextures.get(0).getValue();
+                int frames = texHeight / texWidth;
+                while(tick < frames) {
+                    Gui.drawModalRectWithCustomSizedTexture(x, y, 0, (tick * texWidth), texWidth, texWidth, texWidth, texWidth);
+                    tick++;
+                    if(tick == frames) {
+                        tick = 0;
+                    }
+                }
+            } else {
+                Gui.drawScaledCustomSizeModalRect(x, y, 0, 0, width, height, width, height, width, height);
+            }
+        } catch (Exception e) {
+            themeLog.error("Error occurred drawing texture " + element.name() + ", is theme invalid?", e);
+        }
+    }
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/themes/Theme.java b/src/main/java/io/polyfrost/oneconfig/themes/Theme.java
index cc88e4a..bd6ee80 100644
--- a/src/main/java/io/polyfrost/oneconfig/themes/Theme.java
+++ b/src/main/java/io/polyfrost/oneconfig/themes/Theme.java
@@ -7,14 +7,11 @@ import net.minecraft.client.Minecraft;
 import net.minecraft.client.renderer.texture.DynamicTexture;
 import net.minecraft.client.resources.FileResourcePack;
 import net.minecraft.util.ResourceLocation;
-import org.jetbrains.annotations.NotNull;
 
 import javax.imageio.ImageIO;
 import java.awt.*;
 import java.awt.image.BufferedImage;
 import java.io.*;
-import java.util.ArrayList;
-import java.util.List;
 
 @SuppressWarnings("unused")
 public class Theme extends FileResourcePack {
@@ -36,11 +33,7 @@ public class Theme extends FileResourcePack {
     private final String description;
     private final String title;
     private final int version;
-    private final ResourceLocation iconsLoc;
-    private final ResourceLocation modIconsLoc;
-    private final ResourceLocation smallIconsLoc;
-    private final ResourceLocation logoLoc;
-    private final ResourceLocation logoLocSmall;
+    private final TextureManager manager;
 
 
 
@@ -89,12 +82,11 @@ public class Theme extends FileResourcePack {
         this.description = description;
         this.version = version;
 
-        iconsLoc = createLargeIconAtlas();
-        smallIconsLoc = createSmallIconAtlas();
-        modIconsLoc = createModIconsAtlas();
-        logoLoc = getLocationFromName("textures/logos/logo.png");
-        logoLocSmall = getLocationFromName("textures/logos/logo_small.png");
-        Themes.themeLog.info("Successfully loaded theme and created atlases in " + ((float) (System.nanoTime() - start)) / 1000000f + "ms");
+        manager = new TextureManager(this);
+        if(Themes.VERSION != version) {
+            Themes.themeLog.warn("Theme was made for a different version of OneConfig! This may cause issues in the GUI.");
+        }
+        Themes.themeLog.info("Successfully loaded theme in " + ((float) (System.nanoTime() - start)) / 1000000f + "ms");
 
     }
 
@@ -116,88 +108,6 @@ public class Theme extends FileResourcePack {
 
     }
 
-    /**
-     * Create the large icon atlas from this theme.
-     */
-    private ResourceLocation createLargeIconAtlas() {
-        try {
-            List<BufferedImage> icons = new ArrayList<>();
-            icons.add(ImageIO.read(getResource("textures/icons/discord.png")));
-            icons.add(ImageIO.read(getResource("textures/icons/docs.png")));
-            icons.add(ImageIO.read(getResource("textures/icons/feedback.png")));
-            icons.add(ImageIO.read(getResource("textures/icons/guide.png")));
-            icons.add(ImageIO.read(getResource("textures/icons/hudsettings.png")));
-            icons.add(ImageIO.read(getResource("textures/icons/modsettings.png")));
-            icons.add(ImageIO.read(getResource("textures/icons/store.png")));
-            icons.add(ImageIO.read(getResource("textures/icons/themes.png")));
-            icons.add(ImageIO.read(getResource("textures/icons/update.png")));
-            return createAtlasFromList(icons, 128);
-        } catch (Exception e) {
-            Themes.themeLog.error("Failed to create large icon atlas, is pack invalid?", e);
-            return null;
-        }
-    }
-
-    /**
-     * Create the small icon atlas for this theme.
-     */
-    private ResourceLocation createSmallIconAtlas() {
-        try {
-            List<BufferedImage> icons = new ArrayList<>();
-            icons.add(ImageIO.read(getResource("textures/smallicons/backarrow.png")));
-            icons.add(ImageIO.read(getResource("textures/smallicons/close.png")));
-            icons.add(ImageIO.read(getResource("textures/smallicons/forward.png")));
-            icons.add(ImageIO.read(getResource("textures/smallicons/home.png")));
-            icons.add(ImageIO.read(getResource("textures/smallicons/magnify.png")));
-            icons.add(ImageIO.read(getResource("textures/smallicons/minimize.png")));
-            icons.add(ImageIO.read(getResource("textures/smallicons/search.png")));
-            return createAtlasFromList(icons, 32);
-        } catch (Exception e) {
-            Themes.themeLog.error("Failed to create small icon atlas, is pack invalid?", e);
-            return null;
-        }
-    }
-
-    /**
-     * Create mod icon atlas for this theme.
-     */
-    private ResourceLocation createModIconsAtlas() {
-        try {
-            List<BufferedImage> icons = new ArrayList<>();
-            icons.add(ImageIO.read(getResource("textures/mod/allmods.png")));
-            icons.add(ImageIO.read(getResource("textures/mod/hudmods.png")));
-            icons.add(ImageIO.read(getResource("textures/mod/hypixel.png")));
-            icons.add(ImageIO.read(getResource("textures/mod/performance.png")));
-            icons.add(ImageIO.read(getResource("textures/mod/pvp.png")));
-            icons.add(ImageIO.read(getResource("textures/mod/qolmods.png")));
-            icons.add(ImageIO.read(getResource("textures/mod/skyblock.png")));
-            icons.add(ImageIO.read(getResource("textures/mod/utilities.png")));
-            return createAtlasFromList(icons, 32);
-        } catch (Exception e) {
-            Themes.themeLog.error("Failed to create mod icon atlas, is pack invalid?", e);
-            return null;
-        }
-    }
-
-
-    /**
-     * Create a texture atlas from the given list of images, vertically stacked.
-     * @param images List of BufferedImages to use
-     * @param imageSize image size in pixels (note: images must be square)
-     * @return ResourceLocation of the atlas
-     */
-    public static ResourceLocation createAtlasFromList(@NotNull List<BufferedImage> images, int imageSize) {
-        BufferedImage out = new BufferedImage(imageSize, (images.size() * imageSize), BufferedImage.TYPE_INT_ARGB);
-        Graphics2D graphics2D = out.createGraphics();
-        int i = 0;
-        for (BufferedImage img : images) {
-            graphics2D.drawImage(img, null, 0, i);
-            i += imageSize;
-        }
-        graphics2D.dispose();
-        return mc.getTextureManager().getDynamicTextureLocation(String.valueOf(i), new DynamicTexture(out));
-    }
-
 
     /**
      * get a ResourceLocation of an image in the current theme.
@@ -337,38 +247,10 @@ public class Theme extends FileResourcePack {
     }
 
     /**
-     * Get the large icon atlas.
-     */
-    public ResourceLocation getLargeIconAtlas() {
-        return iconsLoc;
-    }
-
-    /**
-     * Get the small icon atlas.
-     */
-    public ResourceLocation getSmallIconAtlas() {
-        return smallIconsLoc;
-    }
-
-    /**
-     * Get the mod icon atlas.
-     */
-    public ResourceLocation getModIconsAtlas() {
-        return modIconsLoc;
-    }
-
-    /**
-     * Get the logo for OneConfig as specified by this theme.
-     */
-    public ResourceLocation getOneConfigLogo() {
-        return logoLoc;
-    }
-
-    /**
-     * Get the small logo for OneConfig as specified by this theme.
+     * Get the texture manager for this theme, with all drawing utilities.
      */
-    public ResourceLocation getSmallOneConfigLogo() {
-        return logoLocSmall;
+    public TextureManager getTextureManager() {
+        return manager;
     }
 
 }
diff --git a/src/main/java/io/polyfrost/oneconfig/themes/ThemeElement.java b/src/main/java/io/polyfrost/oneconfig/themes/ThemeElement.java
new file mode 100644
index 0000000..f0be82a
--- /dev/null
+++ b/src/main/java/io/polyfrost/oneconfig/themes/ThemeElement.java
@@ -0,0 +1,42 @@
+package io.polyfrost.oneconfig.themes;
+
+public enum ThemeElement {
+    DISCORD("textures/icons/discord.png", 128),
+    DOCS("textures/icons/docs.png", 128),
+    FEEDBACK("textures/icons/feedback.png", 128),
+    GUIDE("textures/icons/guide.png", 128),
+    HUD_SETTINGS("textures/icons/hudsettings.png", 128),
+    MOD_SETTINGS("textures/icons/modsettings.png", 128),
+    STORE("textures/icons/store.png", 128),
+    THEMES("textures/icons/themes.png", 128),
+    UPDATE("textures/icons/update.png", 128),
+
+    BACK_ARROW("textures/smallicons/backarrow.png", 32),
+    CLOSE("textures/smallicons/close.png", 32),
+    FORWARD_ARROW("textures/smallicons/forward.png", 32),
+    HOME("textures/smallicons/home.png", 32),
+    MAGNIFY("textures/smallicons/magnify.png", 32),
+    MINIMIZE("textures/smallicons/minimize.png", 32),
+    SEARCH("textures/smallicons/backarrow.png", 32),
+
+    ALL_MODS("textures/mod/allmods.png", 32),
+    HUD_MODS("textures/mod/hudmods.png", 32),
+    QOL_MODS("textures/mod/qolmods.png", 32),
+    HYPIXEL("textures/mod/hypixel.png", 32),
+    PERFORMANCE("textures/mod/performance.png", 32),
+    PVP("textures/mod/pvp.png", 32),
+    SKYBLOCK("textures/mod/skyblock.png", 32),
+    UTILITIES("textures/mod/utilities.png", 32),
+
+    LOGO("textures/logos/logo.png", 128),
+    SMALL_LOGO("textures/logos/logo_small.png", 32);
+
+
+    public final String location;
+    public final int size;
+
+    ThemeElement(String location, int size) {
+        this.location = location;
+        this.size = size;
+    }
+}
diff --git a/src/main/java/io/polyfrost/oneconfig/themes/Themes.java b/src/main/java/io/polyfrost/oneconfig/themes/Themes.java
index 7bff29c..38e5df7 100644
--- a/src/main/java/io/polyfrost/oneconfig/themes/Themes.java
+++ b/src/main/java/io/polyfrost/oneconfig/themes/Themes.java
@@ -12,6 +12,7 @@ import java.util.List;
 import java.util.Objects;
 
 public class Themes {
+    public static final int VERSION = 0;
     public static Theme activeTheme;
     public static final Logger themeLog = LogManager.getLogger("OneConfig Themes");
 
-- 
cgit