Prechádzať zdrojové kódy

Translations restructure

Lortseam 4 rokov pred
rodič
commit
6ad5e72e1e

+ 10 - 4
src/main/java/me/lortseam/completeconfig/Config.java

@@ -3,23 +3,25 @@ package me.lortseam.completeconfig;
 import com.google.gson.GsonBuilder;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonSyntaxException;
-import lombok.AccessLevel;
-import lombok.RequiredArgsConstructor;
 import me.lortseam.completeconfig.api.ConfigCategory;
 import me.lortseam.completeconfig.collection.CollectionMap;
 import me.lortseam.completeconfig.serialization.CollectionMapDeserializer;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
-@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
 public class Config extends CollectionMap {
 
     private static final Logger LOGGER = LogManager.getLogger();
 
     private final JsonElement json;
 
+    Config(String modID, JsonElement json) {
+        super("config." + modID);
+        this.json = json;
+    }
+
     void registerTopLevelCategory(ConfigCategory category) {
-        fill(category);
+        fill(modTranslationKey, category);
         try {
             new GsonBuilder()
                     .registerTypeAdapter(CollectionMapDeserializer.TYPE, new CollectionMapDeserializer(this, category.getConfigCategoryID()))
@@ -30,4 +32,8 @@ public class Config extends CollectionMap {
         }
     }
 
+    public String getModTranslationKey() {
+        return modTranslationKey;
+    }
+
 }

+ 4 - 4
src/main/java/me/lortseam/completeconfig/ConfigManager.java

@@ -35,8 +35,8 @@ public final class ConfigManager {
     ConfigManager(String modID) {
         this.modID = modID;
         jsonPath = Paths.get(FabricLoader.getInstance().getConfigDir().toString(), modID + ".json");
-        config = new Config(load());
-        guiBuilder = new GuiBuilder(modID, config);
+        config = new Config(modID, load());
+        guiBuilder = new GuiBuilder(this, config);
     }
 
     private JsonElement load() {
@@ -74,8 +74,8 @@ public final class ConfigManager {
         setCustomGuiSupplier(guiBuilder);
     }
 
-    public Screen buildScreen(Screen parent) {
-        return guiBuilder.buildScreen(parent, this::save);
+    public Screen buildScreen(Screen parentScreen) {
+        return guiBuilder.buildScreen(parentScreen, this::save);
     }
 
     /**

+ 5 - 0
src/main/java/me/lortseam/completeconfig/ConfigMap.java

@@ -1,12 +1,17 @@
 package me.lortseam.completeconfig;
 
+import lombok.AccessLevel;
+import lombok.RequiredArgsConstructor;
 import org.apache.commons.lang3.StringUtils;
 
 import java.util.LinkedHashMap;
 import java.util.Map;
 
+@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
 public abstract class ConfigMap<T> extends LinkedHashMap<String, T> {
 
+    protected final String modTranslationKey;
+
     @Override
     public T put(String id, T value) {
         check(id, value);

+ 9 - 0
src/main/java/me/lortseam/completeconfig/api/ConfigEntry.java

@@ -2,6 +2,7 @@ package me.lortseam.completeconfig.api;
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import me.lortseam.completeconfig.entry.EnumOptions.DisplayType;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -67,6 +68,14 @@ public @interface ConfigEntry {
 
     }
 
+    @Target(ElementType.FIELD)
+    @Retention(RetentionPolicy.RUNTIME)
+    @interface EnumOptions {
+
+        DisplayType displayType() default DisplayType.DROPDOWN;
+
+    }
+
     @Target(ElementType.FIELD)
     @Retention(RetentionPolicy.RUNTIME)
     @interface Ignore {

+ 25 - 8
src/main/java/me/lortseam/completeconfig/collection/Collection.java

@@ -1,30 +1,47 @@
 package me.lortseam.completeconfig.collection;
 
 import lombok.Getter;
-import lombok.RequiredArgsConstructor;
 import me.lortseam.completeconfig.api.ConfigCategory;
 import me.lortseam.completeconfig.api.ConfigEntryContainer;
 import me.lortseam.completeconfig.exception.IllegalAnnotationTargetException;
+import net.minecraft.text.Text;
+import net.minecraft.text.TranslatableText;
 
 import java.lang.reflect.Modifier;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.stream.Collectors;
 
-@RequiredArgsConstructor
 public class Collection {
 
+    private final String modTranslationKey;
+    @Getter
+    private final String translationKey;
     @Getter
     private final EntryMap entries;
     @Getter
     private final CollectionMap collections;
 
-    Collection(ConfigEntryContainer container) {
-        this(new EntryMap(), new CollectionMap());
-        fill(container);
+    Collection(String modTranslationKey, String parentTranslationKey, ConfigCategory category) {
+        this.modTranslationKey = modTranslationKey;
+        String categoryID = category.getConfigCategoryID();
+        if (parentTranslationKey == null) {
+            translationKey = categoryID;
+        } else {
+            translationKey = parentTranslationKey + "." + categoryID;
+        }
+        entries = new EntryMap(modTranslationKey);
+        collections = new CollectionMap(modTranslationKey);
+        fill(category);
+    }
+
+    public Text getText() {
+        return new TranslatableText(translationKey);
     }
 
     private void fill(ConfigEntryContainer container) {
-        entries.fill(container);
+        entries.fill(this, container);
         List<ConfigEntryContainer> containers = new ArrayList<>();
         for (Class<? extends ConfigEntryContainer> clazz : container.getClasses()) {
             containers.addAll(Arrays.stream(clazz.getDeclaredFields()).filter(field -> {
@@ -55,7 +72,7 @@ public class Collection {
         containers.addAll(Arrays.asList(container.getTransitiveConfigEntryContainers()));
         for (ConfigEntryContainer c : containers) {
             if (c instanceof ConfigCategory) {
-                collections.fill((ConfigCategory) c);
+                collections.fill(translationKey, (ConfigCategory) c);
             } else {
                 fill(c);
             }

+ 6 - 2
src/main/java/me/lortseam/completeconfig/collection/CollectionMap.java

@@ -9,9 +9,13 @@ public class CollectionMap extends ConfigMap<Collection> {
 
     private static final Logger LOGGER = LogManager.getLogger();
 
-    protected void fill(ConfigCategory category) {
+    protected CollectionMap(String modTranslationKey) {
+        super(modTranslationKey);
+    }
+
+    protected void fill(String parentTranslationKey, ConfigCategory category) {
         String categoryID = category.getConfigCategoryID();
-        Collection collection = new Collection(category);
+        Collection collection = new Collection(modTranslationKey, parentTranslationKey, category);
         if (collection.getEntries().isEmpty() && collection.getCollections().isEmpty()) {
             LOGGER.warn("[CompleteConfig] Category " + categoryID + " is empty!");
             return;

+ 25 - 8
src/main/java/me/lortseam/completeconfig/collection/EntryMap.java

@@ -6,6 +6,7 @@ import me.lortseam.completeconfig.api.ConfigEntry;
 import me.lortseam.completeconfig.api.ConfigEntryContainer;
 import me.lortseam.completeconfig.api.ConfigEntryListener;
 import me.lortseam.completeconfig.entry.Entry;
+import me.lortseam.completeconfig.entry.EnumOptions;
 import me.lortseam.completeconfig.exception.IllegalAnnotationParameterException;
 import me.lortseam.completeconfig.exception.IllegalAnnotationTargetException;
 import me.lortseam.completeconfig.exception.IllegalModifierException;
@@ -18,7 +19,11 @@ import java.util.LinkedHashMap;
 
 public class EntryMap extends ConfigMap<Entry> {
 
-    void fill(ConfigEntryContainer container) {
+    EntryMap(String modTranslationKey) {
+        super(modTranslationKey);
+    }
+
+    void fill(Collection parent, ConfigEntryContainer container) {
         LinkedHashMap<String, Entry> containerEntries = new LinkedHashMap<>();
         for (Class<? extends ConfigEntryContainer> clazz : container.getClasses()) {
             Arrays.stream(clazz.getDeclaredMethods()).filter(method -> !Modifier.isStatic(method.getModifiers()) && method.isAnnotationPresent(ConfigEntryListener.class)).forEach(method -> {
@@ -37,7 +42,7 @@ public class EntryMap extends ConfigMap<Entry> {
                 if (method.getParameterCount() != 1) {
                     throw new IllegalArgumentException("Listener method " + method + " has wrong number of parameters");
                 }
-                Entry<?> entry = Entry.of(fieldName, fieldClass);
+                Entry<?> entry = Entry.of(parent, fieldName, fieldClass);
                 if (method.getParameterTypes()[0] != entry.getType()) {
                     throw new IllegalArgumentException("Listener method " + method + " has wrong argument type");
                 }
@@ -65,12 +70,12 @@ public class EntryMap extends ConfigMap<Entry> {
                 if (!field.isAccessible()) {
                     field.setAccessible(true);
                 }
-                Entry<?> entry = Entry.of(field, container);
+                Entry<?> entry = Entry.of(parent, field, container);
                 if (field.isAnnotationPresent(ConfigEntry.class)) {
                     ConfigEntry entryAnnotation = field.getDeclaredAnnotation(ConfigEntry.class);
                     String customTranslationKey = entryAnnotation.customTranslationKey();
                     if (!StringUtils.isBlank(customTranslationKey)) {
-                        entry.setCustomTranslationKey(customTranslationKey);
+                        entry.setCustomTranslationKey(modTranslationKey + "."  + customTranslationKey);
                     }
                     String[] customTooltipKeys = entryAnnotation.customTooltipKeys();
                     if (customTooltipKeys.length > 0) {
@@ -79,7 +84,7 @@ public class EntryMap extends ConfigMap<Entry> {
                                 throw new IllegalAnnotationParameterException("Tooltip key(s) of entry field " + field + " must not be blank");
                             }
                         }
-                        entry.setCustomTooltipKeys(customTooltipKeys);
+                        entry.setCustomTooltipTranslationKeys(Arrays.stream(customTooltipKeys).map(key -> modTranslationKey + "." + key).toArray(String[]::new));
                     }
                     entry.setForceUpdate(entryAnnotation.forceUpdate());
                 }
@@ -89,25 +94,37 @@ public class EntryMap extends ConfigMap<Entry> {
                     }
                     ConfigEntry.Bounded.Integer bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Integer.class);
                     entry.getExtras().setBounds(bounds.min(), bounds.max(), bounds.slider());
-                } else if (field.isAnnotationPresent(ConfigEntry.Bounded.Long.class)) {
+                }
+                if (field.isAnnotationPresent(ConfigEntry.Bounded.Long.class)) {
                     if (field.getType() != long.class && field.getType() != Long.class) {
                         throw new IllegalAnnotationTargetException("Cannot apply Long bound to non Long field " + field);
                     }
                     ConfigEntry.Bounded.Long bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Long.class);
                     entry.getExtras().setBounds(bounds.min(), bounds.max(), bounds.slider());
-                } else if (field.isAnnotationPresent(ConfigEntry.Bounded.Float.class)) {
+                }
+                if (field.isAnnotationPresent(ConfigEntry.Bounded.Float.class)) {
                     if (field.getType() != float.class && field.getType() != Float.class) {
                         throw new IllegalAnnotationTargetException("Cannot apply Float bound to non Float field " + field);
                     }
                     ConfigEntry.Bounded.Float bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Float.class);
                     entry.getExtras().setBounds(bounds.min(), bounds.max(), false);
-                } else if (field.isAnnotationPresent(ConfigEntry.Bounded.Double.class)) {
+                }
+                if (field.isAnnotationPresent(ConfigEntry.Bounded.Double.class)) {
                     if (field.getType() != double.class && field.getType() != Double.class) {
                         throw new IllegalAnnotationTargetException("Cannot apply Double bound to non Double field " + field);
                     }
                     ConfigEntry.Bounded.Double bounds = field.getDeclaredAnnotation(ConfigEntry.Bounded.Double.class);
                     entry.getExtras().setBounds(bounds.min(), bounds.max(), false);
                 }
+                if (Enum.class.isAssignableFrom(field.getType())) {
+                    if (field.isAnnotationPresent(ConfigEntry.EnumOptions.class)) {
+                        entry.getExtras().setEnumOptions(field.getDeclaredAnnotation(ConfigEntry.EnumOptions.class).displayType());
+                    } else {
+                        entry.getExtras().setEnumOptions(EnumOptions.DisplayType.getDefault());
+                    }
+                } else if (field.isAnnotationPresent(ConfigEntry.EnumOptions.class)) {
+                    throw new IllegalAnnotationTargetException("Cannot apply enum options to non enum field " + field);
+                }
                 clazzEntries.put(field.getName(), entry);
             });
             //TODO: Quite hacky solution to sort the entries (superclasses first)

+ 54 - 14
src/main/java/me/lortseam/completeconfig/entry/Entry.java

@@ -1,8 +1,14 @@
 package me.lortseam.completeconfig.entry;
 
 import com.google.common.collect.MoreCollectors;
-import lombok.*;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.Setter;
 import me.lortseam.completeconfig.api.ConfigEntryContainer;
+import me.lortseam.completeconfig.collection.Collection;
+import net.minecraft.client.resource.language.I18n;
+import net.minecraft.text.Text;
+import net.minecraft.text.TranslatableText;
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 
@@ -12,34 +18,33 @@ import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.util.*;
 
-@RequiredArgsConstructor(access = AccessLevel.PRIVATE)
 public class Entry<T> {
 
     private static final Logger LOGGER = LogManager.getLogger();
     private static final Set<Entry> ENTRIES = new HashSet<>();
 
-    public static Entry<?> of(String fieldName, Class<? extends ConfigEntryContainer> parentClass) {
+    public static Entry<?> of(Collection parent, String fieldName, Class<? extends ConfigEntryContainer> parentClass) {
         try {
             Field field = parentClass.getDeclaredField(fieldName);
             if (!field.isAccessible()) {
                 field.setAccessible(true);
             }
-            return of(field);
+            return of(parent, field);
         } catch (NoSuchFieldException e) {
             throw new RuntimeException(e);
         }
     }
 
-    private static <T> Entry<T> of(Field field) {
+    private static <T> Entry<T> of(Collection parent, Field field) {
         return ENTRIES.stream().filter(entry -> entry.field.equals(field)).collect(MoreCollectors.toOptional()).orElseGet(() -> {
-            Entry<T> entry = new Entry<>(field, (Class<T>) field.getType());
+            Entry<T> entry = new Entry<>(parent, field, (Class<T>) field.getType());
             ENTRIES.add(entry);
             return entry;
         });
     }
 
-    public static <T> Entry<T> of(Field field, ConfigEntryContainer parentObject) {
-        Entry<T> entry = of(field);
+    public static <T> Entry<T> of(Collection parent, Field field, ConfigEntryContainer parentObject) {
+        Entry<T> entry = of(parent, field);
         entry.parentObject = parentObject;
         entry.defaultValue = entry.getValue();
         return entry;
@@ -53,18 +58,37 @@ public class Entry<T> {
     private ConfigEntryContainer parentObject;
     @Getter
     private T defaultValue;
-    @Getter
-    @Setter
-    private String customTranslationKey;
-    @Getter
-    @Setter
-    private String[] customTooltipKeys;
+    private String translationKey;
+    private String[] tooltipTranslationKeys;
     @Getter
     private Extras<T> extras = new Extras<>(this);
     private final List<Listener> listeners = new ArrayList<>();
     @Setter
     private boolean forceUpdate;
 
+    private Entry(Collection parent, Field field, Class<T> type) {
+        translationKey = parent.getTranslationKey() + "." + field.getName();
+        String defaultTooltipTranslationKey = translationKey + ".tooltip";
+        if (I18n.hasTranslation(defaultTooltipTranslationKey)) {
+            tooltipTranslationKeys = new String[] {defaultTooltipTranslationKey};
+        } else {
+            List<String> defaultTooltipTranslationKeys = new ArrayList<>();
+            for(int i = 0;; i++) {
+                String key = defaultTooltipTranslationKey + "." + i;
+                if(I18n.hasTranslation(key)) {
+                    defaultTooltipTranslationKeys.add(key);
+                } else {
+                    if (!defaultTooltipTranslationKeys.isEmpty()) {
+                        tooltipTranslationKeys = defaultTooltipTranslationKeys.toArray(new String[0]);
+                    }
+                    break;
+                }
+            }
+        }
+        this.field = field;
+        this.type = type;
+    }
+
     public T getValue() {
         if (updateValueIfNecessary()) {
             return getValue();
@@ -126,6 +150,22 @@ public class Entry<T> {
         listeners.add(new Listener(method, parentObject));
     }
 
+    public void setCustomTranslationKey(String translationKey) {
+        this.translationKey = translationKey;
+    }
+
+    public Text getText() {
+        return new TranslatableText(translationKey);
+    }
+
+    public void setCustomTooltipTranslationKeys(String[] tooltipTranslationKeys) {
+        this.tooltipTranslationKeys = tooltipTranslationKeys;
+    }
+
+    public Optional<Text[]> getTooltip() {
+        return tooltipTranslationKeys != null ? Optional.of(Arrays.stream(tooltipTranslationKeys).map(TranslatableText::new).toArray(Text[]::new)) : Optional.empty();
+    }
+
     @AllArgsConstructor
     private static class Listener {
 

+ 34 - 0
src/main/java/me/lortseam/completeconfig/entry/EnumOptions.java

@@ -0,0 +1,34 @@
+package me.lortseam.completeconfig.entry;
+
+import lombok.AccessLevel;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import me.lortseam.completeconfig.api.ConfigEntry;
+
+@AllArgsConstructor(access = AccessLevel.PACKAGE)
+public class EnumOptions {
+
+    @Getter
+    private final DisplayType displayType;
+
+    public enum DisplayType {
+
+        BUTTON, DROPDOWN;
+
+        private static final DisplayType defaultValue;
+
+        static {
+            try {
+                defaultValue = (DisplayType) ConfigEntry.EnumOptions.class.getDeclaredMethod("displayType").getDefaultValue();
+            } catch (NoSuchMethodException e) {
+                throw new RuntimeException(e);
+            }
+        }
+
+        public static DisplayType getDefault() {
+            return defaultValue;
+        }
+
+    }
+
+}

+ 6 - 0
src/main/java/me/lortseam/completeconfig/entry/Extras.java

@@ -11,6 +11,8 @@ public class Extras<T> {
     private final Entry<T> entry;
     @Getter
     private Bounds<T> bounds;
+    @Getter
+    private EnumOptions enumOptions;
 
     public <N extends Number> void setBounds(N min, N max, boolean slider) {
         if (!ClassUtils.isAssignable(entry.getType(), min.getClass()) || !ClassUtils.isAssignable(entry.getType(), max.getClass())) {
@@ -19,4 +21,8 @@ public class Extras<T> {
         bounds = new Bounds<>((T) min, (T) max, slider);
     }
 
+    public void setEnumOptions(EnumOptions.DisplayType displayType) {
+        enumOptions = new EnumOptions(displayType);
+    }
+
 }

+ 20 - 58
src/main/java/me/lortseam/completeconfig/gui/GuiBuilder.java

@@ -2,8 +2,8 @@ package me.lortseam.completeconfig.gui;
 
 import lombok.Getter;
 import lombok.Setter;
-import me.lortseam.completeconfig.CompleteConfig;
 import me.lortseam.completeconfig.Config;
+import me.lortseam.completeconfig.ConfigManager;
 import me.lortseam.completeconfig.collection.Collection;
 import me.shedaniel.clothconfig2.api.AbstractConfigListEntry;
 import me.shedaniel.clothconfig2.api.ConfigBuilder;
@@ -11,90 +11,52 @@ import me.shedaniel.clothconfig2.api.ConfigCategory;
 import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
 import me.shedaniel.clothconfig2.impl.builders.SubCategoryBuilder;
 import net.minecraft.client.gui.screen.Screen;
-import net.minecraft.client.resource.language.I18n;
-import net.minecraft.text.Text;
 import net.minecraft.text.TranslatableText;
-import org.apache.commons.lang3.ArrayUtils;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
 import java.util.function.Supplier;
 
 public class GuiBuilder {
 
-    private static String joinIDs(String... ids) {
-        return String.join(".", ids);
-    }
-
-    private final String modID;
+    private final ConfigManager manager;
     private final Config config;
     @Setter
     private Supplier<ConfigBuilder> supplier = ConfigBuilder::create;
     @Getter
     private final GuiRegistry registry = new GuiRegistry();
 
-    public GuiBuilder(String modID, Config config) {
-        this.modID = modID;
+    public GuiBuilder(ConfigManager manager, Config config) {
+        this.manager = manager;
         this.config = config;
     }
 
-    private String buildTranslationKey(String... ids) {
-        return joinIDs("config", modID, joinIDs(ids));
-    }
-
-    public Screen buildScreen(Screen parent, Runnable savingRunnable) {
+    public Screen buildScreen(Screen parentScreen, Runnable savingRunnable) {
         ConfigBuilder builder = supplier.get();
-        builder.setParentScreen(parent)
-                .setTitle(new TranslatableText(buildTranslationKey("title")))
+        builder.setParentScreen(parentScreen)
+                .setTitle(new TranslatableText(config.getModTranslationKey() + ".title"))
                 .setSavingRunnable(savingRunnable);
-        config.forEach((categoryID, category) -> {
-            ConfigCategory configCategory = builder.getOrCreateCategory(new TranslatableText(buildTranslationKey(categoryID)));
-            for (AbstractConfigListEntry entry : buildCollection(categoryID, category)) {
+        config.values().forEach(collection -> {
+            ConfigCategory configCategory = builder.getOrCreateCategory(collection.getText());
+            for (AbstractConfigListEntry<?> entry : buildCollection(collection)) {
                 configCategory.addEntry(entry);
             }
         });
         return builder.build();
     }
 
-    private List<AbstractConfigListEntry> buildCollection(String parentID, Collection collection) {
-        List<AbstractConfigListEntry> list = new ArrayList<>();
-        collection.getEntries().forEach((entryID, entry) -> {
-            String translationKey = entry.getCustomTranslationKey() != null ? buildTranslationKey(entry.getCustomTranslationKey()) : buildTranslationKey(parentID, entryID);
-            String[] tooltipKeys = entry.getCustomTooltipKeys();
-            if (tooltipKeys != null) {
-                tooltipKeys = Arrays.stream(tooltipKeys).map(this::buildTranslationKey).toArray(String[]::new);
-            } else {
-                String defaultTooltipKey = joinIDs(translationKey, "tooltip");
-                if (I18n.hasTranslation(defaultTooltipKey)) {
-                    tooltipKeys = new String[] {defaultTooltipKey};
-                } else {
-                    for(int i = 0;; i++) {
-                        String key = joinIDs(defaultTooltipKey, String.valueOf(i));
-                        if(I18n.hasTranslation(key)) {
-                            if (tooltipKeys == null) {
-                                tooltipKeys = new String[]{key};
-                            } else {
-                                tooltipKeys = ArrayUtils.add(tooltipKeys, key);
-                            }
-                        } else {
-                            break;
-                        }
-                    }
-                }
-            }
-            list.add(((Optional<GuiProvider>) CompleteConfig.getManager(modID).get().getGuiRegistry().getProvider(entry)).orElseGet(() -> {
-                throw new UnsupportedOperationException("Could not find gui provider for field " + entry.getField());
-            }).build(new TranslatableText(translationKey), entry.getField(), entry.getValue(), entry.getDefaultValue(), tooltipKeys != null ? Optional.of(Arrays.stream(tooltipKeys).map(TranslatableText::new).toArray(Text[]::new)) : Optional.empty(), entry.getExtras(), entry::setValue));
-        });
-        collection.getCollections().forEach((subcategoryID, c) -> {
-            String id = joinIDs(parentID, subcategoryID);
-            SubCategoryBuilder subBuilder = ConfigEntryBuilder.create().startSubCategory(new TranslatableText(buildTranslationKey(id)));
-            subBuilder.addAll(buildCollection(id, c));
-            list.add(subBuilder.build());
+    private List<AbstractConfigListEntry> buildCollection(Collection collection) {
+        List<AbstractConfigListEntry> collectionGui = new ArrayList<>();
+        collection.getEntries().values().forEach(entry -> collectionGui.add(((Optional<GuiProvider>) manager.getGuiRegistry().getProvider(entry)).orElseGet(() -> {
+            throw new UnsupportedOperationException("Could not find gui provider for field " + entry.getField());
+        }).build(entry.getText(), entry.getField(), entry.getValue(), entry.getDefaultValue(), entry.getTooltip(), entry.getExtras(), entry::setValue)));
+        collection.getCollections().values().forEach(c -> {
+            SubCategoryBuilder subBuilder = ConfigEntryBuilder.create().startSubCategory(c.getText());
+            subBuilder.addAll(buildCollection(c));
+            collectionGui.add(subBuilder.build());
         });
-        return list;
+        return collectionGui;
     }
     
 }

+ 13 - 4
src/main/java/me/lortseam/completeconfig/gui/GuiRegistry.java

@@ -3,13 +3,17 @@ package me.lortseam.completeconfig.gui;
 import com.google.common.base.CaseFormat;
 import com.google.common.collect.Lists;
 import me.lortseam.completeconfig.entry.Entry;
+import me.lortseam.completeconfig.entry.EnumOptions;
 import me.shedaniel.clothconfig2.api.ConfigEntryBuilder;
 import net.minecraft.text.TranslatableText;
 import org.apache.commons.lang3.ArrayUtils;
 
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
 
 public class GuiRegistry {
 
@@ -36,10 +40,14 @@ public class GuiRegistry {
         registerProvider(provider, (field, extras) -> true, types);
     }
 
-    public void registerBoundedProvider(GuiProvider<?> provider, boolean slider, Class... types) {
+    private void registerBoundedProvider(GuiProvider<?> provider, boolean slider, Class... types) {
         registerProvider(provider, (field, extras) -> extras.getBounds() != null && extras.getBounds().isSlider() == slider, types);
     }
 
+    private void registerEnumProvider(GuiProvider<? extends Enum> provider, EnumOptions.DisplayType enumDisplayType) {
+        registerProvider(provider, (field, extras) -> Enum.class.isAssignableFrom(field.getType()) && extras.getEnumOptions().getDisplayType() == enumDisplayType);
+    }
+
     public <T> void registerGenericProvider(GuiProvider<T> provider, Class<?> type, Class... genericTypes) {
         registerProvider(provider, (field, extras) -> {
             Type fieldType = field.getGenericType();
@@ -167,7 +175,7 @@ public class GuiRegistry {
                 .build(),
                 String.class
         );
-        registerProvider((GuiProvider<? extends Enum>) (text, field, value, defaultValue, tooltip, extras, saveConsumer) -> ConfigEntryBuilder
+        registerEnumProvider((GuiProvider<? extends Enum>) (text, field, value, defaultValue, tooltip, extras, saveConsumer) -> ConfigEntryBuilder
                 .create()
                 .startEnumSelector(text, (Class<Enum>) field.getType(), value)
                 .setDefaultValue(defaultValue)
@@ -176,8 +184,9 @@ public class GuiRegistry {
                 .setEnumNameProvider(e -> new TranslatableText(((TranslatableText) text).getKey() + "." + CaseFormat.UPPER_UNDERSCORE.to(CaseFormat.LOWER_CAMEL, e.name())))
                 .setSaveConsumer(saveConsumer)
                 .build(),
-                (field, extras) -> Enum.class.isAssignableFrom(field.getType())
+                EnumOptions.DisplayType.BUTTON
         );
+        //TODO: Enum as dropdown
         registerGenericProvider((GuiProvider<List<Integer>>) (text, field, value, defaultValue, tooltip, extras, saveConsumer) -> ConfigEntryBuilder
                 .create()
                 .startIntList(text, value)

+ 3 - 3
src/main/java/me/lortseam/completeconfig/serialization/CollectionDeserializer.java

@@ -5,10 +5,8 @@ import com.google.gson.reflect.TypeToken;
 import me.lortseam.completeconfig.collection.Collection;
 import me.lortseam.completeconfig.collection.CollectionMap;
 import me.lortseam.completeconfig.collection.EntryMap;
-import me.lortseam.completeconfig.entry.Entry;
 
 import java.lang.reflect.Type;
-import java.util.LinkedHashMap;
 import java.util.Map;
 
 public class CollectionDeserializer implements JsonDeserializer<Collection> {
@@ -26,7 +24,9 @@ public class CollectionDeserializer implements JsonDeserializer<Collection> {
                 entries.add(entry.getKey(), entry.getValue());
             }
         }
-        return new Collection(context.deserialize(collections, new TypeToken<CollectionMap>() {}.getType()), context.deserialize(entries, new TypeToken<EntryMap>() {}.getType()));
+        context.deserialize(collections, new TypeToken<CollectionMap>() {}.getType());
+        context.deserialize(entries, new TypeToken<EntryMap>() {}.getType());
+        return null;
     }
 
 }

+ 3 - 3
src/main/java/me/lortseam/completeconfig/serialization/CollectionMapDeserializer.java

@@ -30,14 +30,14 @@ public class CollectionMapDeserializer implements JsonDeserializer<CollectionMap
     public CollectionMap deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
         LinkedHashMap<String, JsonElement> map = GSON.fromJson(json, new TypeToken<LinkedHashMap<String, JsonElement>>() {}.getType());
         if (collectionID == null) {
-            map.forEach(this::deserialize);
+            map.forEach(this::deserializeCollection);
         } else {
-            deserialize(collectionID, map.get(collectionID));
+            deserializeCollection(collectionID, map.get(collectionID));
         }
         return null;
     }
 
-    private void deserialize(String collectionID, JsonElement element) {
+    private void deserializeCollection(String collectionID, JsonElement element) {
         Collection collection = configMap.get(collectionID);
         if (collection == null) {
             return;