diff --git a/fml/src/main/java/net/minecraftforge/fml/client/GuiModList.java b/fml/src/main/java/net/minecraftforge/fml/client/GuiModList.java index d33a83df8..39c18085b 100644 --- a/fml/src/main/java/net/minecraftforge/fml/client/GuiModList.java +++ b/fml/src/main/java/net/minecraftforge/fml/client/GuiModList.java @@ -19,6 +19,9 @@ import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; import javax.imageio.ImageIO; @@ -26,6 +29,7 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.gui.FontRenderer; import net.minecraft.client.gui.GuiButton; import net.minecraft.client.gui.GuiScreen; +import net.minecraft.client.gui.GuiTextField; import net.minecraft.client.renderer.Tessellator; import net.minecraft.client.renderer.WorldRenderer; import net.minecraft.client.renderer.texture.DynamicTexture; @@ -49,6 +53,28 @@ import com.google.common.base.Strings; */ public class GuiModList extends GuiScreen { + private enum SortType + { + NORMAL(24), A_TO_Z(25), Z_TO_A(26); + + private int buttonID; + + private SortType(int buttonID) + { + this.buttonID = buttonID; + } + + public static SortType getTypeForButton(GuiButton button) + { + for (SortType t : values()) { + if (t.buttonID == button.id) { + return t; + } + } + return null; + } + } + private GuiScreen mainMenu; private GuiSlotModList modList; private int selected = -1; @@ -59,6 +85,15 @@ public class GuiModList extends GuiScreen private GuiButton disableModButton; private ResourceLocation cachedLogo; private Dimension cachedLogoDimensions; + + private int buttonMargin = 1; + private int numButtons = SortType.values().length; + + private String lastFilterText = ""; + + private GuiTextField search; + private boolean sorted = false; + private SortType sortType = SortType.NORMAL; /** * @param mainMenu @@ -68,6 +103,7 @@ public class GuiModList extends GuiScreen this.mainMenu=mainMenu; this.mods=new ArrayList(); FMLClientHandler.instance().addSpecialModEntries(mods); + // Add child mods to their parent's list for (ModContainer mod : Loader.instance().getModList()) { if (mod.getMetadata()!=null && mod.getMetadata().parentMod==null && !Strings.isNullOrEmpty(mod.getMetadata().parent)) { String parentMod = mod.getMetadata().parent; @@ -81,7 +117,7 @@ public class GuiModList extends GuiScreen } else if (mod.getMetadata()!=null && mod.getMetadata().parentMod!=null) { - continue; + continue; } mods.add(mod); } @@ -96,21 +132,133 @@ public class GuiModList extends GuiScreen listWidth=Math.max(listWidth,getFontRenderer().getStringWidth(mod.getVersion()) + 10); } listWidth=Math.min(listWidth, 150); - this.buttonList.add(new GuiButton(6, this.width / 2 - 75, this.height - 38, I18n.format("gui.done"))); - configModButton = new GuiButton(20, 10, this.height - 60, this.listWidth, 20, "Config"); - disableModButton = new GuiButton(21, 10, this.height - 38, this.listWidth, 20, "Disable"); - this.buttonList.add(configModButton); - this.buttonList.add(disableModButton); this.modList=new GuiSlotModList(this, mods, listWidth); this.modList.registerScrollButtons(this.buttonList, 7, 8); + + this.buttonList.add(new GuiButton(6, ((modList.right + this.width) / 2) - 100, this.height - 38, I18n.format("gui.done"))); + configModButton = new GuiButton(20, 10, this.height - 49, this.listWidth, 20, "Config"); + disableModButton = new GuiButton(21, 10, this.height - 27, this.listWidth, 20, "Disable"); + this.buttonList.add(configModButton); + this.buttonList.add(disableModButton); + + search = new GuiTextField(0, getFontRenderer(), 12, modList.bottom + 17, modList.listWidth - 4, 14); + search.setFocused(true); + search.setCanLoseFocus(true); + + int width = (modList.listWidth / numButtons); + int x = 10, y = 10; + GuiButton normalSort = new GuiButton(SortType.NORMAL.buttonID, x, y, width - buttonMargin, 20, I18n.format("fml.menu.mods.normal")); + normalSort.enabled = false; + buttonList.add(normalSort); + x += width + buttonMargin; + buttonList.add(new GuiButton(SortType.A_TO_Z.buttonID, x, y, width - buttonMargin, 20, "A-Z")); + x += width + buttonMargin; + buttonList.add(new GuiButton(SortType.Z_TO_A.buttonID, x, y, width - buttonMargin, 20, "Z-A")); + } + + @Override + protected void mouseClicked(int x, int y, int button) throws IOException + { + super.mouseClicked(x, y, button); + search.mouseClicked(x, y, button); + if (button == 1 && x >= search.xPosition && x < search.xPosition + this.width && y >= search.yPosition && y < search.yPosition + this.height) { + search.setText(""); + } + } + + @Override + protected void keyTyped(char c, int keyCode) throws IOException + { + super.keyTyped(c, keyCode); + search.textboxKeyTyped(c, keyCode); + } + + @Override + public void updateScreen() + { + super.updateScreen(); + search.updateCursorCounter(); + + if (!search.getText().equals(lastFilterText)) + { + reloadMods(); + sorted = false; + } + + if (!sorted) + { + switch (sortType) + { + case A_TO_Z: + Collections.sort(modList.getMods(), new Comparator() + { + @Override + public int compare(ModContainer o1, ModContainer o2) + { + return o1.getName().toLowerCase().compareTo(o2.getName().toLowerCase()); + } + }); + break; + case Z_TO_A: + Collections.sort(modList.getMods(), new Comparator() + { + @Override + public int compare(ModContainer o1, ModContainer o2) + { + return o2.getName().toLowerCase().compareTo(o1.getName().toLowerCase()); + } + }); + break; + default: + reloadMods(); + break; + } + mods = modList.getMods(); + selected = modList.selectedIndex = mods.indexOf(selectedMod); + sorted = true; + } + } + + private void reloadMods() + { + ArrayList mods = modList.getMods(); + mods.clear(); + for (ModContainer m : Loader.instance().getActiveModList()) + { + // If it passes the filter, and is not a child mod + if (m.getName().toLowerCase().contains(search.getText().toLowerCase()) && m.getMetadata().parentMod == null) + { + mods.add(m); + } + } + this.mods = mods; + lastFilterText = search.getText(); } @Override protected void actionPerformed(GuiButton button) throws IOException { if (button.enabled) { - switch (button.id) + SortType type = SortType.getTypeForButton(button); + + if (type != null) { + for (GuiButton b : (List) buttonList) + { + if (SortType.getTypeForButton(b) != null) + { + b.enabled = true; + } + } + button.enabled = false; + sorted = false; + sortType = type; + this.mods = modList.getMods(); + } + else + { + switch (button.id) + { case 6: this.mc.displayGuiScreen(this.mainMenu); return; @@ -126,6 +274,7 @@ public class GuiModList extends GuiScreen FMLLog.log(Level.ERROR, e, "There was a critical issue trying to build the config GUI for %s", selectedMod.getModId()); } return; + } } } super.actionPerformed(button); @@ -274,6 +423,11 @@ public class GuiModList extends GuiScreen disableModButton.visible = false; } super.drawScreen(p_571_1_, p_571_2_, p_571_3_); + + String text = I18n.format("fml.menu.mods.search"); + int x = ((10 + modList.right) / 2) - (getFontRenderer().getStringWidth(text) / 2); + getFontRenderer().drawString(text, x, modList.bottom + 5, 0xFFFFFF); + search.drawTextBox(); } Minecraft getMinecraftInstance() { diff --git a/fml/src/main/java/net/minecraftforge/fml/client/GuiScrollingList.java b/fml/src/main/java/net/minecraftforge/fml/client/GuiScrollingList.java index be38ab001..5810d691c 100644 --- a/fml/src/main/java/net/minecraftforge/fml/client/GuiScrollingList.java +++ b/fml/src/main/java/net/minecraftforge/fml/client/GuiScrollingList.java @@ -31,7 +31,7 @@ public abstract class GuiScrollingList protected final int listHeight; protected final int top; protected final int bottom; - private final int right; + protected final int right; protected final int left; protected final int slotHeight; private int scrollUpActionId; @@ -41,7 +41,7 @@ public abstract class GuiScrollingList private float initialMouseClickY = -2.0F; private float scrollFactor; private float scrollDistance; - private int selectedIndex = -1; + protected int selectedIndex = -1; private long lastClickTime = 0L; private boolean field_25123_p = true; private boolean field_27262_q; diff --git a/fml/src/main/java/net/minecraftforge/fml/client/GuiSlotModList.java b/fml/src/main/java/net/minecraftforge/fml/client/GuiSlotModList.java index 69c489f21..606dfdd9d 100644 --- a/fml/src/main/java/net/minecraftforge/fml/client/GuiSlotModList.java +++ b/fml/src/main/java/net/minecraftforge/fml/client/GuiSlotModList.java @@ -16,8 +16,8 @@ import java.util.ArrayList; import net.minecraft.client.renderer.Tessellator; import net.minecraftforge.fml.common.Loader; -import net.minecraftforge.fml.common.ModContainer; import net.minecraftforge.fml.common.LoaderState.ModState; +import net.minecraftforge.fml.common.ModContainer; /** * @author cpw @@ -30,7 +30,7 @@ public class GuiSlotModList extends GuiScrollingList public GuiSlotModList(GuiModList parent, ArrayList mods, int listWidth) { - super(parent.getMinecraftInstance(), listWidth, parent.height, 32, parent.height - 66 + 4, 10, 35); + super(parent.getMinecraftInstance(), listWidth, parent.height, 32, parent.height - 88 + 4, 10, 35); this.parent=parent; this.mods=mods; } @@ -64,6 +64,11 @@ public class GuiSlotModList extends GuiScrollingList { return (this.getSize()) * 35 + 1; } + + ArrayList getMods() + { + return mods; + } @Override protected void drawSlot(int listIndex, int var2, int var3, int var4, Tessellator var5) diff --git a/fml/src/main/resources/assets/fml/lang/en_US.lang b/fml/src/main/resources/assets/fml/lang/en_US.lang index 270d2ff98..4ba2237a8 100644 --- a/fml/src/main/resources/assets/fml/lang/en_US.lang +++ b/fml/src/main/resources/assets/fml/lang/en_US.lang @@ -82,4 +82,6 @@ fml.configgui.tooltip.default=[default: %s] fml.configgui.tooltip.defaultNumeric=[range: %s ~ %s, default: %s] fml.menu.mods=Mods +fml.menu.mods.normal=Normal +fml.menu.mods.search=Search: fml.menu.modoptions=Mod Options...