Compare commits

...
29 changed files with 2856 additions and 1311 deletions

No files matched your search

+173 -91
View File
@@ -14,11 +14,13 @@ import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.WeakHashMap;
import javax.annotation.Nullable;
@@ -98,8 +100,7 @@ public class BookmarkPanel extends PanelWidget {
ItemStackMetadata meta = topItemIndex >= 0 ? BGrid.metadata.get(topItemIndex) : null;
if (meta != null && meta.recipeId != null) {
while (topItemIndex > 0 && meta.groupId == BGrid.metadata.get(topItemIndex - 1).groupId
&& meta.recipeId.equals(BGrid.metadata.get(topItemIndex - 1).recipeId)) {
while (topItemIndex > 0 && meta.equalsRecipe(BGrid.metadata.get(topItemIndex - 1))) {
topItemIndex--;
}
@@ -118,8 +119,7 @@ public class BookmarkPanel extends PanelWidget {
if (meta != null && meta.recipeId != null) {
int size = BGrid.size();
while (bottomItemIndex < size - 1 && meta.groupId == BGrid.metadata.get(bottomItemIndex + 1).groupId
&& meta.recipeId.equals(BGrid.metadata.get(bottomItemIndex + 1).recipeId)) {
while (bottomItemIndex < size - 1 && meta.equalsRecipe(BGrid.metadata.get(bottomItemIndex + 1))) {
bottomItemIndex++;
}
@@ -148,9 +148,21 @@ public class BookmarkPanel extends PanelWidget {
this.fluidDisplay = fluidDisplay;
}
public ItemStackMetadata(BookmarkRecipeId recipeId, NBTTagCompound nbTag, boolean ingredient, Integer groupId) {
this(recipeId, nbTag.getInteger("Count"), ingredient, groupId, nbTag.hasKey("gtFluidName"));
}
public ItemStackMetadata copy() {
return new ItemStackMetadata(this.recipeId, this.factor, this.ingredient, this.groupId, this.fluidDisplay);
}
public boolean equalsRecipe(ItemStackMetadata meta) {
return equalsRecipe(meta.recipeId, meta.groupId);
}
public boolean equalsRecipe(BookmarkRecipeId recipeId, int groupId) {
return groupId == this.groupId && recipeId != null && recipeId.equals(this.recipeId);
}
}
public static enum BookmarkViewMode {
@@ -163,6 +175,26 @@ public class BookmarkPanel extends PanelWidget {
LOADED
}
public static class BookmarkRecipe {
public String handlerName = "";
public List<ItemStack> result = new ArrayList<>();
public List<ItemStack> ingredients = new ArrayList<>();
public BookmarkRecipe(ItemStack... result) {
this.result.addAll(Arrays.asList(result));
}
public BookmarkRecipeId getRecipeId() {
if (!handlerName.isEmpty() && !ingredients.isEmpty()) {
return new BookmarkRecipeId(handlerName, ingredients);
}
return null;
}
}
protected static class BookmarkGroup {
public BookmarkCraftingChain crafting = null;
@@ -607,8 +639,7 @@ public class BookmarkPanel extends PanelWidget {
final ArrayList<Integer> items = new ArrayList<>();
for (int index = idx; index < size; index++) {
if (this.metadata.get(index).groupId == groupId
&& meta.recipeId.equals(this.metadata.get(index).recipeId)) {
if (meta.equalsRecipe(this.metadata.get(index))) {
sortingRank.put(index, (this.metadata.get(index).ingredient ? 1 : -1) * dir);
items.add(index);
}
@@ -756,7 +787,7 @@ public class BookmarkPanel extends PanelWidget {
final ItemStackMetadata meta = getMetadata(idx);
if (meta.groupId == groupId
&& (recipeId == null && meta.recipeId == null
|| recipeId != null && meta.recipeId != null && recipeId.equals(meta.recipeId))
|| recipeId != null && recipeId.equals(meta.recipeId))
&& StackInfo.equalItemAndNBT(stackA, getItem(idx), true)) {
return idx;
}
@@ -797,9 +828,15 @@ public class BookmarkPanel extends PanelWidget {
}
protected void removeRecipe(int idx, boolean removeFullRecipe) {
final ItemStackMetadata meta = getMetadata(idx);
final ItemStackMetadata meta = this.metadata.get(idx);
if (meta.recipeId != null && (removeFullRecipe || !meta.ingredient)) {
if (!removeFullRecipe && meta.recipeId != null && !meta.ingredient) {
final Optional<ItemStackMetadata> result = this.metadata.stream()
.filter(m -> m != meta && !m.ingredient && meta.equalsRecipe(m)).findAny();
removeFullRecipe = !result.isPresent();
}
if (meta.recipeId != null && removeFullRecipe) {
removeRecipe(meta.recipeId, meta.groupId);
} else {
removeItem(idx);
@@ -807,12 +844,9 @@ public class BookmarkPanel extends PanelWidget {
}
protected void removeRecipe(BookmarkRecipeId recipeIdA, int groupId) {
BookmarkRecipeId recipeIdB;
for (int slotIndex = metadata.size() - 1; slotIndex >= 0; slotIndex--) {
recipeIdB = metadata.get(slotIndex).recipeId;
if (recipeIdB != null && metadata.get(slotIndex).groupId == groupId && recipeIdB.equals(recipeIdA)) {
if (metadata.get(slotIndex).equalsRecipe(recipeIdA, groupId)) {
removeItem(slotIndex);
}
}
@@ -889,14 +923,12 @@ public class BookmarkPanel extends PanelWidget {
drawRect(rect.x, rect.y, rect.w, rect.h, 0x9966CCFF); // exports
}
} else if (focus != null && meta.recipeId != null
&& meta.groupId == getMetadata(focus.slotIndex).groupId
&& meta.recipeId.equals(this.getRecipeId(focus.slotIndex))) {
drawRect(rect.x, rect.y, rect.w, rect.h, meta.ingredient ? 0x6645DA75 : 0x9966CCFF); // highlight
// recipe
} else {
super.beforeDrawSlot(focus, idx, rect);
}
} else if (focus != null && meta.equalsRecipe(getMetadata(focus.slotIndex))) {
drawRect(rect.x, rect.y, rect.w, rect.h, meta.ingredient ? 0x6645DA75 : 0x9966CCFF); // highlight
// recipe
} else {
super.beforeDrawSlot(focus, idx, rect);
}
}
@@ -920,11 +952,9 @@ public class BookmarkPanel extends PanelWidget {
if (groupMeta.crafting != null && meta.groupId == this.focusedGroupId
&& groupMeta.crafting.multiplier.containsKey(stack)) {
multiplier = this.groups.get(meta.groupId).crafting.multiplier.get(stack);
} else if (focus != null && meta.factor > 0
&& meta.groupId == this.metadata.get(focus.slotIndex).groupId
&& meta.recipeId.equals(this.metadata.get(focus.slotIndex).recipeId)) {
multiplier = StackInfo.itemStackToNBT(stack).getInteger("Count") / meta.factor;
}
} else if (focus != null && meta.factor > 0 && meta.equalsRecipe(getMetadata(focus.slotIndex))) {
multiplier = StackInfo.itemStackToNBT(stack).getInteger("Count") / meta.factor;
}
}
}
@@ -1219,7 +1249,7 @@ public class BookmarkPanel extends PanelWidget {
addItem(itemStack, true);
}
public void addItem(ItemStack itemStack, boolean saveStackSize) {
public void addItem(ItemStack itemStack, boolean saveSize) {
final BookmarkGrid BGrid = (BookmarkGrid) grid;
int idx = BGrid.indexOf(itemStack, true);
@@ -1227,7 +1257,7 @@ public class BookmarkPanel extends PanelWidget {
BGrid.removeItem(idx);
}
addOrRemoveItem(itemStack, null, null, false, saveStackSize);
addOrRemoveItem(itemStack, null, null, false, saveSize);
}
public void addOrRemoveItem(ItemStack stackA) {
@@ -1235,7 +1265,7 @@ public class BookmarkPanel extends PanelWidget {
}
public void addOrRemoveItem(ItemStack stackover, final String handlerName, final List<PositionedStack> ingredients,
boolean saveIngredients, boolean saveStackSize) {
boolean saveIngredients, boolean saveSize) {
loadBookmarksIfNeeded();
final Point mousePos = getMousePosition();
@@ -1245,61 +1275,35 @@ public class BookmarkPanel extends PanelWidget {
if (slot != null && StackInfo.equalItemAndNBT(slot.item, stackover, true)) {
BGrid.removeRecipe(slot.slotIndex, saveIngredients);
} else {
final NBTTagCompound nbTagA = StackInfo.itemStackToNBT(stackover, saveStackSize);
final ItemStack normalizedA = StackInfo.loadFromNBT(nbTagA, saveStackSize ? nbTagA.getInteger("Count") : 0);
BookmarkRecipeId recipeId = null;
if (handlerName != "" && ingredients != null) {
if (!handlerName.isEmpty() && ingredients != null) {
recipeId = new BookmarkRecipeId(handlerName, ingredients);
}
final int idx = BGrid.indexOf(normalizedA, recipeId);
final int idx = BGrid.indexOf(stackover, recipeId);
if (idx != -1) {
BGrid.removeRecipe(idx, saveIngredients);
} else {
} else if (saveIngredients && !handlerName.isEmpty() && ingredients != null) {
BookmarkRecipe recipe = new BookmarkRecipe(stackover);
recipe.handlerName = handlerName;
if (saveIngredients && handlerName != "" && ingredients != null) {
final Map<String, Integer> ingredientCount = new HashMap<>();
final Map<String, NBTTagCompound> uniqueIngredients = new LinkedHashMap<>();
BGrid.removeRecipe(recipeId, BookmarkGrid.DEFAULT_GROUP_ID);
for (PositionedStack stack : ingredients) {
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack.item, saveStackSize);
final String GUID = StackInfo.getItemStackGUID(stack.item);
if (!uniqueIngredients.containsKey(GUID)) {
ingredientCount.put(GUID, nbTag.getInteger("Count"));
uniqueIngredients.put(GUID, nbTag);
} else {
ingredientCount.put(GUID, ingredientCount.get(GUID) + nbTag.getInteger("Count"));
}
}
for (String GUID : uniqueIngredients.keySet()) {
BGrid.addItem(
StackInfo.loadFromNBT(
uniqueIngredients.get(GUID),
saveStackSize ? ingredientCount.get(GUID) : 0),
new ItemStackMetadata(
recipeId != null ? recipeId.copy() : null,
ingredientCount.get(GUID),
true,
BookmarkGrid.DEFAULT_GROUP_ID,
uniqueIngredients.get(GUID).hasKey("gtFluidName")));
}
for (PositionedStack stack : ingredients) {
recipe.ingredients.add(stack.item);
}
BGrid.addItem(
normalizedA,
new ItemStackMetadata(
recipeId,
nbTagA.getInteger("Count"),
false,
BookmarkGrid.DEFAULT_GROUP_ID,
nbTagA.hasKey("gtFluidName")));
addRecipe(recipe, saveSize);
} else {
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stackover);
final ItemStack normalized = StackInfo.loadFromNBT(nbTag, saveSize ? nbTag.getInteger("Count") : 0);
final ItemStackMetadata metadata = new ItemStackMetadata(
recipeId,
nbTag,
false,
BookmarkGrid.DEFAULT_GROUP_ID);
BGrid.addItem(normalized, metadata);
}
}
@@ -1307,6 +1311,92 @@ public class BookmarkPanel extends PanelWidget {
saveBookmarks();
}
public void addRecipe(BookmarkRecipe recipe, boolean saveSize) {
addRecipe(recipe, saveSize, BookmarkGrid.DEFAULT_GROUP_ID);
}
public void addRecipe(BookmarkRecipe recipe, boolean saveSize, int groupId) {
final BookmarkGrid BGrid = (BookmarkGrid) grid;
final BookmarkRecipeId recipeId = recipe.getRecipeId();
if (!BGrid.groups.containsKey(groupId)) {
groupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
if (recipeId != null) {
final Map<String, NBTTagCompound> uniqueIngredients = new LinkedHashMap<>();
BGrid.removeRecipe(recipeId, groupId);
for (ItemStack stack : recipe.ingredients) {
final String GUID = StackInfo.getItemStackGUID(stack);
final NBTTagCompound nbTagU = uniqueIngredients.get(GUID);
final NBTTagCompound nbTagS = StackInfo.itemStackToNBT(stack);
if (nbTagU == null) {
uniqueIngredients.put(GUID, nbTagS);
} else {
nbTagU.setInteger("Count", nbTagU.getInteger("Count") + nbTagS.getInteger("Count"));
}
}
for (String GUID : uniqueIngredients.keySet()) {
final NBTTagCompound nbTag = uniqueIngredients.get(GUID);
final ItemStack normalized = StackInfo.loadFromNBT(nbTag, saveSize ? nbTag.getInteger("Count") : 0);
final ItemStackMetadata metadata = new ItemStackMetadata(recipeId.copy(), nbTag, true, groupId);
BGrid.addItem(normalized, metadata);
}
}
for (ItemStack stack : recipe.result) {
final NBTTagCompound nbTag = StackInfo.itemStackToNBT(stack);
final ItemStack normalized = StackInfo.loadFromNBT(nbTag, saveSize ? nbTag.getInteger("Count") : 0);
final ItemStackMetadata metadata = new ItemStackMetadata(recipeId, nbTag, false, groupId);
BGrid.addItem(normalized, metadata);
}
fixCountOfNamespaces();
saveBookmarks();
}
public void addBookmarkGroup(List<ItemStack> items, BookmarkViewMode viewMode) {
List<BookmarkRecipe> recipes = new ArrayList<>();
for (ItemStack stack : items) {
recipes.add(new BookmarkRecipe(stack));
}
addBookmarkGroup(recipes, viewMode, false);
}
public void addBookmarkGroup(List<BookmarkRecipe> recipes, BookmarkViewMode viewMode, boolean crafting) {
if (recipes.isEmpty()) return;
final BookmarkGrid BGrid = (BookmarkGrid) grid;
int groupId = BookmarkGrid.DEFAULT_GROUP_ID;
if (viewMode == null) {
viewMode = BGrid.getViewMode(BookmarkGrid.DEFAULT_GROUP_ID);
}
for (ItemStackMetadata meta : BGrid.metadata) {
if (meta.groupId > groupId) {
groupId = meta.groupId;
}
}
BGrid.groups.put(++groupId, new BookmarkGroup(viewMode, crafting));
for (BookmarkRecipe recipe : recipes) {
addRecipe(recipe, true, groupId);
}
fixCountOfNamespaces();
saveBookmarks();
}
public BookmarkRecipeId getBookmarkRecipeId(int slotIndex) {
ItemStackMetadata meta = ((BookmarkGrid) grid).getMetadata(slotIndex);
return meta.ingredient ? null : meta.recipeId;
@@ -1774,8 +1864,7 @@ public class BookmarkPanel extends PanelWidget {
} else {
for (int i = 0; i < BGrid.metadata.size(); i++) {
if (BGrid.metadata.get(i).recipeId != null && meta.groupId == BGrid.metadata.get(i).groupId
&& meta.recipeId.equals(BGrid.metadata.get(i).recipeId)) {
if (meta.equalsRecipe(BGrid.getMetadata(i))) {
items.add(BGrid.realItems.get(i));
metadata.add(BGrid.metadata.get(i));
}
@@ -1822,7 +1911,7 @@ public class BookmarkPanel extends PanelWidget {
} else if (ySlot <= 0.25) {
if (BGrid.getViewMode(beforeGroupId) == BookmarkViewMode.TODO_LIST
&& !existsRecipeIdInGroupId(beforeGroupId, sortMeta.recipeId)) {
&& !existsRecipeIdInGroupId(sortMeta.recipeId, beforeGroupId)) {
BGrid.moveItem(this.sortableItem, mouseOverSlot.slotIndex, beforeGroupId, true);
}
@@ -1832,12 +1921,12 @@ public class BookmarkPanel extends PanelWidget {
&& (afterGroupId != BookmarkGrid.DEFAULT_GROUP_ID
|| BGrid.getViewMode(overGroupId) == BookmarkViewMode.DEFAULT)
&& BGrid.getViewMode(BookmarkGrid.DEFAULT_GROUP_ID) == BookmarkViewMode.TODO_LIST
&& !existsRecipeIdInGroupId(BookmarkGrid.DEFAULT_GROUP_ID, sortMeta.recipeId)) {
&& !existsRecipeIdInGroupId(sortMeta.recipeId, BookmarkGrid.DEFAULT_GROUP_ID)) {
beforeGroupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
if (BGrid.getViewMode(beforeGroupId) == BookmarkViewMode.TODO_LIST
&& !existsRecipeIdInGroupId(beforeGroupId, sortMeta.recipeId)) {
&& !existsRecipeIdInGroupId(sortMeta.recipeId, beforeGroupId)) {
BGrid.moveItem(this.sortableItem, mouseOverSlot.slotIndex, beforeGroupId, true);
}
@@ -1848,12 +1937,12 @@ public class BookmarkPanel extends PanelWidget {
|| BGrid.getViewMode(overGroupId) == BookmarkViewMode.DEFAULT)
&& afterGroupId != BookmarkGrid.DEFAULT_GROUP_ID
&& BGrid.getViewMode(BookmarkGrid.DEFAULT_GROUP_ID) == BookmarkViewMode.TODO_LIST
&& !existsRecipeIdInGroupId(BookmarkGrid.DEFAULT_GROUP_ID, sortMeta.recipeId)) {
&& !existsRecipeIdInGroupId(sortMeta.recipeId, BookmarkGrid.DEFAULT_GROUP_ID)) {
afterGroupId = BookmarkGrid.DEFAULT_GROUP_ID;
}
if (BGrid.getViewMode(afterGroupId) == BookmarkViewMode.TODO_LIST
&& !existsRecipeIdInGroupId(afterGroupId, sortMeta.recipeId)) {
&& !existsRecipeIdInGroupId(sortMeta.recipeId, afterGroupId)) {
BGrid.moveItem(
this.sortableItem,
BGrid.getRowItemIndex(overRowIndex, false),
@@ -1864,7 +1953,7 @@ public class BookmarkPanel extends PanelWidget {
} else if (ySlot >= 0.75) {
if (BGrid.getViewMode(afterGroupId) == BookmarkViewMode.TODO_LIST
&& !existsRecipeIdInGroupId(afterGroupId, sortMeta.recipeId)) {
&& !existsRecipeIdInGroupId(sortMeta.recipeId, afterGroupId)) {
BGrid.moveItem(
this.sortableItem,
BGrid.getRowItemIndex(overRowIndex, false),
@@ -1909,12 +1998,11 @@ public class BookmarkPanel extends PanelWidget {
super.mouseDragged(mousex, mousey, button, heldTime);
}
private boolean existsRecipeIdInGroupId(int groupId, BookmarkRecipeId recipeId) {
private boolean existsRecipeIdInGroupId(BookmarkRecipeId recipeId, int groupId) {
if (recipeId == null) return false;
for (ItemStackMetadata meta : ((BookmarkGrid) grid).metadata) {
if (meta.groupId == groupId && this.sortableItem.metadata.indexOf(meta) == -1
&& recipeId.equals(meta.recipeId)) {
if (meta.equalsRecipe(recipeId, groupId) && this.sortableItem.metadata.indexOf(meta) == -1) {
return true;
}
}
@@ -2077,18 +2165,12 @@ public class BookmarkPanel extends PanelWidget {
}
if (NEIClientUtils.shiftKey()) {
ItemStackMetadata ingrMeta;
for (int slotIndex = grid.size() - 1; slotIndex >= 0; slotIndex--) {
ingrMeta = BGrid.getMetadata(slotIndex);
if (ingrMeta.recipeId != null && ingrMeta.groupId == overMeta.groupId
&& ingrMeta.recipeId.equals(overMeta.recipeId)
&& slotIndex != slot.slotIndex) {
if (overMeta.equalsRecipe(BGrid.getMetadata(slotIndex)) && slotIndex != slot.slotIndex) {
items.put(slotIndex, shiftStackSize(BGrid, slotIndex, shift, shiftMultiplier));
}
}
}
items.put(slot.slotIndex, shiftStackSize(BGrid, slot.slotIndex, shift, shiftMultiplier));
@@ -0,0 +1,364 @@
package codechicken.nei;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import net.minecraft.item.ItemStack;
import net.minecraftforge.oredict.OreDictionary;
import org.apache.commons.io.IOUtils;
import codechicken.nei.ItemList.AllMultiItemFilter;
import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.EverythingItemFilter;
import codechicken.nei.ItemList.NegatedItemFilter;
import codechicken.nei.ItemList.NothingItemFilter;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.PresetsList.PresetMode;
import codechicken.nei.api.ItemFilter;
import cpw.mods.fml.common.registry.GameData;
public class CollapsibleItems {
protected static interface ISearchParserProvider {
public ItemFilter getFilter(String searchText);
default Predicate<String> getMatcher(String searchText) {
if (searchText.length() >= 3 && searchText.startsWith("r/") && searchText.endsWith("/")) {
try {
Pattern pattern = Pattern.compile(
searchText.substring(2, searchText.length() - 1),
Pattern.MULTILINE | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
return value -> pattern.matcher(value).find();
} catch (PatternSyntaxException ignored) {}
} else if (!searchText.isEmpty()) {
return value -> value.toLowerCase().contains(searchText);
}
return null;
}
}
protected static class GroupTokenParser {
protected final HashMap<Character, ISearchParserProvider> searchProviders = new HashMap<>();
public void addProvider(char prefix, ISearchParserProvider provider) {
this.searchProviders.put(prefix, provider);
}
public ItemFilter getFilter(String filterText) {
final String[] parts = filterText.toLowerCase().trim().split("\\|");
final List<ItemFilter> searchTokens = Arrays.stream(parts).map(s -> parseSearchText(s))
.filter(s -> s != null && !s.filters.isEmpty()).collect(Collectors.toCollection(ArrayList::new));
if (searchTokens.isEmpty()) {
return new EverythingItemFilter();
} else if (searchTokens.size() == 1) {
return searchTokens.get(0);
} else {
return new AnyMultiItemFilter(searchTokens);
}
}
private AllMultiItemFilter parseSearchText(String filterText) {
if (filterText.isEmpty()) {
return null;
}
final String[] tokens = filterText.split("\\s+");
final AllMultiItemFilter searchTokens = new AllMultiItemFilter();
for (String token : tokens) {
token = token.trim();
boolean ignore = token.startsWith("!");
if (ignore) {
token = token.substring(1);
}
if (token.isEmpty()) {
continue;
}
ISearchParserProvider provider = this.searchProviders.get(token.charAt(0));
if (provider != null) {
token = token.substring(1);
} else {
provider = this.searchProviders.get('\0');
}
ItemFilter filter = parseToken(ignore ? "!" + token : token, provider);
if (filter != null) {
searchTokens.filters.add(filter);
}
}
return searchTokens;
}
private ItemFilter parseToken(String token, ISearchParserProvider provider) {
final String[] parts = token.split(",");
final AnyMultiItemFilter includeFilter = new AnyMultiItemFilter();
final AnyMultiItemFilter expludeFilter = new AnyMultiItemFilter();
final AllMultiItemFilter groupFilter = new AllMultiItemFilter();
for (String part : parts) {
boolean ignore = part.startsWith("!");
if (ignore) {
part = part.substring(1);
}
ItemFilter filter = provider.getFilter(part);
if (filter == null) {
continue;
}
if (ignore) {
expludeFilter.filters.add(filter);
} else {
includeFilter.filters.add(filter);
}
}
if (!includeFilter.filters.isEmpty()) {
groupFilter.filters.add(includeFilter);
}
if (!expludeFilter.filters.isEmpty()) {
groupFilter.filters.add(new NegatedItemFilter(expludeFilter));
}
return groupFilter.filters.isEmpty() ? null : groupFilter;
}
}
protected static class IdentifierFilter implements ISearchParserProvider {
@Override
public ItemFilter getFilter(String searchText) {
if (Pattern.matches("^\\d+(-\\d+)*$", searchText)) {
final Predicate<Integer> filter = generateDamageFilter(searchText);
return (stack) -> filter.test(stack.getItemDamage());
}
Predicate<String> matcher = getMatcher(searchText);
if (matcher != null) {
return stack -> matcher.test(getStringIdentifier(stack));
}
return null;
}
protected String getStringIdentifier(ItemStack stack) {
String name = GameData.getItemRegistry().getNameForObject(stack.getItem());
return name == null || name.isEmpty() ? "Unknown:Unknown" : name;
}
protected Predicate<Integer> generateDamageFilter(String searchText) {
String[] range = searchText.split("-");
if (range.length == 1) {
final int damage = Integer.parseInt(range[0]);
return (dmg) -> dmg == damage;
} else {
final int damageStart = Integer.parseInt(range[0]);
final int damageEnd = Integer.parseInt(range[1]);
return (dmg) -> dmg >= damageStart && dmg <= damageEnd;
}
}
}
protected static class OreDictionaryFilter implements ISearchParserProvider {
@Override
public ItemFilter getFilter(String searchText) {
Predicate<String> matcher = getMatcher(searchText);
if (matcher != null) {
return stack -> matches(stack, matcher);
}
return null;
}
protected boolean matches(ItemStack stack, Predicate<String> matcher) {
return IntStream.of(OreDictionary.getOreIDs(stack))
.anyMatch(id -> matcher.test(OreDictionary.getOreName(id)));
}
}
protected static class GroupItem {
protected static int lastGroupIndex = 0;
public final int groupIndex;
public final ItemFilter filter;
public boolean expanded = false;
public GroupItem(ItemFilter filter) {
this.groupIndex = lastGroupIndex++;
this.filter = filter;
}
public boolean matches(ItemStack stack) {
return this.filter.matches(stack);
}
}
protected static final GroupTokenParser groupParser = new GroupTokenParser();
protected final Map<Integer, GroupItem> groups = new ConcurrentHashMap<>();
protected final Map<ItemStack, Integer> cache = new ConcurrentHashMap<>();
static {
groupParser.addProvider('\0', new IdentifierFilter());
groupParser.addProvider('$', new OreDictionaryFilter());
}
public void reload() {
GroupItem.lastGroupIndex = 0;
this.groups.clear();
this.cache.clear();
for (int i = PresetsList.presets.size() - 1; i >= 0; i--) {
Preset preset = PresetsList.presets.get(i);
if (preset.enabled && preset.mode == PresetMode.GROUP) {
addGroup(preset);
}
}
loadCollapsibleItems();
if (ItemList.loadFinished) {
LayoutManager.markItemsDirty();
}
}
protected void loadCollapsibleItems() {
File file = NEIClientConfig.collapsibleItemsFile;
if (!file.exists()) {
try (FileWriter writer = new FileWriter(file)) {
NEIClientConfig.logger.info("Creating default collapsible items list {}", file);
URL defaultCollapsibleItemsResource = ClientHandler.class
.getResource("/assets/nei/cfg/collapsibleitems.cfg");
if (defaultCollapsibleItemsResource != null) {
IOUtils.copy(defaultCollapsibleItemsResource.openStream(), writer);
}
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to save default collapsible items list to file {}", file, e);
}
}
try (FileReader reader = new FileReader(file)) {
NEIClientConfig.logger.info("Loading collapsible items from file {}", file);
IOUtils.readLines(reader).stream().filter((line) -> !line.startsWith("#") && !line.trim().isEmpty())
.forEach(this::addGroup);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load collapsible items from file {}", file, e);
}
}
protected void addGroup(String filterText) {
addGroup(CollapsibleItems.groupParser.getFilter(filterText.trim()));
}
protected void addGroup(ItemFilter filter) {
if (filter == null || filter instanceof EverythingItemFilter || filter instanceof NothingItemFilter) return;
GroupItem group = new GroupItem(filter);
this.groups.put(group.groupIndex, group);
}
public ItemFilter getItemFilter() {
AnyMultiItemFilter filter = new AnyMultiItemFilter();
for (GroupItem group : this.groups.values()) {
filter.filters.add(group.filter);
}
return filter;
}
public void updateCache(final List<ItemStack> items) {
this.cache.clear();
try {
ItemList.forkJoinPool.submit(() -> items.parallelStream().forEach(stack -> {
GroupItem group = this.groups.values().stream().filter(g -> g.matches(stack)).findFirst().orElse(null);
if (group != null) {
this.cache.put(stack, group.groupIndex);
}
})).get();
} catch (Exception e) {
NEIClientConfig.logger.error("Error create collapsible items groups", e);
}
}
public int getGroupIndex(ItemStack stack) {
if (stack == null) {
return -1;
}
return this.cache.getOrDefault(stack, -1);
}
public boolean isExpanded(int groupIndex) {
if (this.groups.containsKey(groupIndex)) {
return this.groups.get(groupIndex).expanded;
}
return true;
}
public void setExpanded(int groupIndex, boolean expanded) {
if (this.groups.containsKey(groupIndex)) {
this.groups.get(groupIndex).expanded = expanded;
}
}
public void toggleGroups(Boolean expanded) {
if (expanded == null) {
expanded = !this.groups.values().stream().filter(g -> g.expanded).findAny().isPresent();
}
for (GroupItem group : this.groups.values()) {
group.expanded = expanded;
}
}
}
@@ -8,7 +8,7 @@ import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
class FormattedTextField extends GuiTextField {
public class FormattedTextField extends GuiTextField {
public static interface TextFormatter {
+48 -7
View File
@@ -2,6 +2,7 @@ package codechicken.nei;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
@@ -38,11 +39,12 @@ public class ItemList {
* Updates to this should be synchronised on this
*/
public static final List<ItemFilterProvider> itemFilterers = new LinkedList<>();
public static final List<ItemsLoadedCallback> loadCallbacks = new LinkedList<>();
public static final CollapsibleItems collapsibleItems = new CollapsibleItems();
private static final HashSet<Item> erroredItems = new HashSet<>();
private static final HashSet<String> stackTraces = new HashSet<>();
private static final HashMap<ItemStack, Integer> ordering = new HashMap<>();
/**
* Unlike {@link LayoutManager#itemsLoaded}, this indicates whether item loading is actually finished or not.
*/
@@ -223,6 +225,38 @@ public class ItemList {
return "";
}
private void updateOrdering(List<ItemStack> items) {
ItemList.ordering.clear();
ItemSorter.sort(items);
if (NEIClientConfig.enableCollapsibleItems()) {
HashMap<Integer, Integer> groups = new HashMap<>();
int orderIndex = 0;
for (ItemStack stack : items) {
final int groupIndex = ItemList.collapsibleItems.getGroupIndex(stack);
if (groupIndex == -1) {
ItemList.ordering.put(stack, orderIndex++);
} else {
if (!groups.containsKey(groupIndex)) {
groups.put(groupIndex, orderIndex++);
}
ItemList.ordering.put(stack, groups.get(groupIndex));
}
}
} else {
int orderIndex = 0;
for (ItemStack stack : items) {
ItemList.ordering.put(stack, orderIndex++);
}
}
}
@Override
@SuppressWarnings("unchecked")
public void execute() {
@@ -230,8 +264,8 @@ public class ItemList {
ThreadOperationTimer timer = getTimer(NEIClientConfig.getItemLoadingTimeout());
loadFinished = false;
LinkedList<ItemStack> items = new LinkedList<>();
LinkedList<ItemStack> permutations = new LinkedList<>();
List<ItemStack> items = new LinkedList<>();
List<ItemStack> permutations = new LinkedList<>();
ListMultimap<Item, ItemStack> itemMap = ArrayListMultimap.create();
timer.setLimit(NEIClientConfig.getItemLoadingTimeout());
@@ -267,9 +301,12 @@ public class ItemList {
ItemList.itemMap = itemMap;
for (ItemsLoadedCallback callback : loadCallbacks) callback.itemsLoaded();
updateFilter.restart();
if (interrupted()) return;
ItemList.collapsibleItems.updateCache(items);
updateOrdering(items);
loadFinished = true;
updateFilter.restart();
}
};
@@ -284,11 +321,15 @@ public class ItemList {
public static final RestartableTask updateFilter = new RestartableTask("NEI Item Filtering") {
private int compare(ItemStack o1, ItemStack o2) {
return Integer.compare(ItemList.ordering.get(o1), ItemList.ordering.get(o2));
}
@Override
public void execute() {
// System.out.println("Executing NEI Item Filtering");
ArrayList<ItemStack> filtered;
if (!loadFinished) return;
ItemFilter filter = getItemListFilter();
ArrayList<ItemStack> filtered;
try {
filtered = ItemList.forkJoinPool.submit(
@@ -302,7 +343,7 @@ public class ItemList {
}
if (interrupted()) return;
ItemSorter.sort(filtered);
filtered.sort(this::compare);
if (interrupted()) return;
ItemPanel.updateItemList(filtered);
}
+333 -10
View File
@@ -1,17 +1,27 @@
package codechicken.nei;
import static codechicken.lib.gui.GuiDraw.drawRect;
import java.awt.Color;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.annotation.Nullable;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.OpenGlHelper;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
public class ItemPanel extends PanelWidget {
public class ItemPanel extends PanelWidget implements IContainerTooltipHandler {
/**
* Backwards compat :-/
@@ -35,6 +45,7 @@ public class ItemPanel extends PanelWidget {
public Button less;
public ItemQuantityField quantity;
public ItemHistoryPanel historyPanel;
public Button toggleGroups;
public static class ItemPanelSlot {
@@ -52,9 +63,29 @@ public class ItemPanel extends PanelWidget {
}
}
protected static class MaskMetadata {
public int groupIndex = -1;
public boolean extended = false;
public Color bgColor = null;
public Color color = null;
public boolean left = false;
public boolean top = false;
public boolean right = false;
public boolean bottom = false;
}
protected static class ItemPanelGrid extends ItemsGrid {
public ArrayList<ItemStack> newItems;
public ArrayList<ItemStack> rawItems;
protected final HashMap<Integer, List<ItemStack>> groupItems = new HashMap<>();
protected final HashMap<Integer, MaskMetadata> maskMetadata = new HashMap<>();
protected boolean forceExpand = false;
public void setItems(ArrayList<ItemStack> items) {
newItems = items;
@@ -62,9 +93,48 @@ public class ItemPanel extends PanelWidget {
public void refresh(GuiContainer gui) {
if (newItems != null) {
realItems = newItems;
newItems = null;
if (this.newItems != null) {
this.groupItems.clear();
this.forceExpand = false;
if (NEIClientConfig.enableCollapsibleItems() && !this.newItems.isEmpty()) {
final Set<Integer> groups = new HashSet<>();
boolean outsideGroup = false;
this.realItems = new ArrayList<>();
this.rawItems = new ArrayList<>(this.newItems);
for (ItemStack stack : this.newItems) {
final int groupIndex = ItemList.collapsibleItems.getGroupIndex(stack);
if (groupIndex == -1) {
this.realItems.add(stack);
outsideGroup = true;
} else {
if (!groups.contains(groupIndex) || ItemList.collapsibleItems.isExpanded(groupIndex)) {
this.realItems.add(stack);
groups.add(groupIndex);
}
if (!this.groupItems.containsKey(groupIndex)) {
this.groupItems.put(groupIndex, new ArrayList<>());
}
this.groupItems.get(groupIndex).add(stack);
}
}
// automatically opens if there are elements from only one group
if (!outsideGroup && groups.size() == 1) {
this.realItems = new ArrayList<>(this.newItems);
this.forceExpand = true;
}
} else {
this.realItems = new ArrayList<>(this.newItems);
}
this.newItems = null;
onItemsChanged();
}
@@ -72,11 +142,170 @@ public class ItemPanel extends PanelWidget {
}
@Override
protected void beforeDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
if (PresetsWidget.inEditMode()) {
if (!PresetsWidget.isHidden(getItem(slotIdx))) drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555);
protected List<Integer> getMask() {
final boolean updateBorders = this.gridMask == null;
final List<Integer> mask = super.getMask();
if (updateBorders) {
calculateGroupBorders(mask);
}
return mask;
}
protected void calculateGroupBorders(List<Integer> mask) {
this.maskMetadata.clear();
if (mask.isEmpty() || this.groupItems.isEmpty()) {
return;
}
final HashMap<Integer, Integer> maskGroup = new HashMap<>();
final Color collapsedColor = new Color(
NEIClientConfig.getSetting("inventory.collapsibleItems.collapsedColor").getHexValue(),
true);
final Color expandedColor = new Color(
NEIClientConfig.getSetting("inventory.collapsibleItems.expandedColor").getHexValue(),
true);
for (int slotIndex = 0; slotIndex < mask.size(); slotIndex++) {
if (mask.get(slotIndex) == null) {
continue;
}
int idx = mask.get(slotIndex);
maskGroup.put(idx, ItemList.collapsibleItems.getGroupIndex(getItem(idx)));
}
for (int slotIndex = 0; slotIndex < mask.size(); slotIndex++) {
if (mask.get(slotIndex) == null) {
continue;
}
int idx = mask.get(slotIndex);
int groupIndex = maskGroup.get(idx);
if (groupIndex == -1 || this.groupItems.get(groupIndex).size() == 1) {
continue;
}
int column = slotIndex % this.columns;
int row = slotIndex / this.columns;
int prevSlotIndex = (row - 1) * this.columns + column;
int nextSlotIndex = (row + 1) * this.columns + column;
MaskMetadata metadata = new MaskMetadata();
metadata.groupIndex = groupIndex;
metadata.extended = this.forceExpand || ItemList.collapsibleItems.isExpanded(groupIndex);
metadata.bgColor = metadata.extended ? expandedColor : collapsedColor;
metadata.color = darkerColor(metadata.bgColor);
metadata.left = column == 0 || idx == 0
|| mask.get(slotIndex - 1) == null
|| maskGroup.getOrDefault(idx - 1, -1) != groupIndex;
metadata.right = column == this.columns - 1 || maskGroup.getOrDefault(idx + 1, -1) != groupIndex;
if (prevSlotIndex >= 0) {
Integer previdx = mask.get(prevSlotIndex);
metadata.top = previdx == null || maskGroup.getOrDefault(previdx, -1) != groupIndex;
} else {
metadata.top = true;
}
if (nextSlotIndex < mask.size()) {
Integer nextidx = mask.get(nextSlotIndex);
metadata.bottom = nextidx == null || maskGroup.getOrDefault(nextidx, -1) != groupIndex;
} else {
metadata.bottom = true;
}
this.maskMetadata.put(idx, metadata);
}
}
@Override
protected void beforeDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
final List<Integer> mask = getMask();
super.beforeDrawItems(mousex, mousey, focused);
for (int i = 0; i < mask.size(); i++) {
if (mask.get(i) != null) {
drawBorder(mask.get(i), getSlotRect(i));
}
}
}
protected void drawBorder(int slotIdx, Rectangle4i rect) {
final MaskMetadata metadata = this.maskMetadata.get(slotIdx);
if (metadata != null) {
final float LINE_WIDTH = 0.75f;
drawRect(rect.x, rect.y, rect.w, rect.h, metadata.bgColor);
if (metadata.left) {
float leftBottom = metadata.bottom ? -LINE_WIDTH : 0;
drawRect(rect.x, rect.y, LINE_WIDTH, rect.h + leftBottom, metadata.color);
}
if (metadata.right) {
float rightTop = metadata.top ? LINE_WIDTH : 0;
drawRect(rect.x + rect.w, rect.y - rightTop, LINE_WIDTH, rect.h + rightTop, metadata.color);
}
if (metadata.top) {
drawRect(rect.x, rect.y - LINE_WIDTH, rect.w, LINE_WIDTH, metadata.color);
}
if (metadata.bottom) {
drawRect(rect.x, rect.y + rect.h - LINE_WIDTH, rect.w, LINE_WIDTH, metadata.color);
}
}
}
private static Color darkerColor(Color color) {
return new Color(
color.getRed(),
color.getGreen(),
color.getBlue(),
Math.min((int) (color.getAlpha() + (255f / 5) * 2), 255));
}
private static void drawRect(double left, double top, double width, double height, Color color) {
Tessellator tessellator = Tessellator.instance;
GL11.glEnable(GL11.GL_BLEND);
GL11.glDisable(GL11.GL_TEXTURE_2D);
OpenGlHelper.glBlendFunc(770, 771, 1, 0);
GL11.glColor4f(
color.getRed() / 255f,
color.getGreen() / 255f,
color.getBlue() / 255f,
color.getAlpha() / 255f);
tessellator.startDrawingQuads();
tessellator.addVertex(left, top + height, 0.0D);
tessellator.addVertex(left + width, top + height, 0.0D);
tessellator.addVertex(left + width, top, 0.0D);
tessellator.addVertex(left, top, 0.0D);
tessellator.draw();
GL11.glEnable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_BLEND);
}
@Override
protected void drawItem(Rectangle4i rect, int slotIdx) {
final MaskMetadata metadata = this.maskMetadata.get(slotIdx);
if (metadata != null && !metadata.extended) {
final List<ItemStack> groupItems = this.groupItems.get(metadata.groupIndex);
GuiContainerManager.drawItems.zLevel -= 10F;
GuiContainerManager.drawItem(rect.x + 1, rect.y - 1, groupItems.get(groupItems.size() - 1), true, "");
GuiContainerManager.drawItems.zLevel += 10F;
GuiContainerManager.drawItem(rect.x - 1, rect.y + 1, getItem(slotIdx), true, "");
} else {
super.beforeDrawSlot(focused, slotIdx, rect);
super.drawItem(rect, slotIdx);
}
}
@@ -88,6 +317,7 @@ public class ItemPanel extends PanelWidget {
public ItemPanel() {
grid = new ItemPanelGrid();
GuiContainerManager.addTooltipHandler(this);
}
public static void updateItemList(ArrayList<ItemStack> newItems) {
@@ -99,6 +329,21 @@ public class ItemPanel extends PanelWidget {
public void init() {
super.init();
toggleGroups = new Button("G") {
@Override
public String getButtonTip() {
return NEIClientUtils.translate("itempanel.collapsed.button.tip");
}
@Override
public boolean onButtonPress(boolean rightclick) {
ItemList.collapsibleItems.toggleGroups(rightclick ? false : null);
ItemList.updateFilter.restart();
return true;
}
};
more = new Button("+") {
@Override
@@ -167,6 +412,18 @@ public class ItemPanel extends PanelWidget {
return gui.height - getMarginTop(gui) - PADDING;
}
@Override
protected int resizeHeader(GuiContainer gui) {
int marginTop = super.resizeHeader(gui);
toggleGroups.w = pageNext.w;
toggleGroups.h = pageNext.h;
toggleGroups.y = pageNext.y;
toggleGroups.x = pageNext.x - toggleGroups.w - 2;
return marginTop;
}
protected int resizeFooter(GuiContainer gui) {
if (!NEIClientConfig.showItemQuantityWidget() && NEIClientConfig.isSearchWidgetCentered()
&& !NEIClientConfig.showHistoryPanelWidget()) {
@@ -224,6 +481,10 @@ public class ItemPanel extends PanelWidget {
LayoutManager.addWidget(quantity);
}
if (NEIClientConfig.enableCollapsibleItems()) {
LayoutManager.addWidget(toggleGroups);
}
if (NEIClientConfig.showHistoryPanelWidget()) {
LayoutManager.addWidget(historyPanel);
}
@@ -251,4 +512,66 @@ public class ItemPanel extends PanelWidget {
return null;
}
@Override
public List<String> handleTooltip(GuiContainer gui, int mousex, int mousey, List<String> currenttip) {
return currenttip;
}
@Override
public List<String> handleItemDisplayName(GuiContainer gui, ItemStack itemstack, List<String> currenttip) {
return currenttip;
}
@Override
public List<String> handleItemTooltip(GuiContainer gui, ItemStack itemstack, int mousex, int mousey,
List<String> currenttip) {
final ItemPanelGrid panelGrid = ((ItemPanelGrid) this.grid);
if (!panelGrid.forceExpand) {
final ItemPanelSlot hoverSlot = getSlotMouseOver(mousex, mousey);
if (hoverSlot != null) {
final MaskMetadata metadata = panelGrid.maskMetadata.get(hoverSlot.slotIndex);
if (metadata != null) {
final List<ItemStack> items = panelGrid.groupItems.get(metadata.groupIndex);
if (items != null && items.size() > 1) {
String message = metadata.extended ? "itempanel.collapsed.hint.collapse"
: "itempanel.collapsed.hint.expand";
currenttip.add(
1,
EnumChatFormatting.GRAY + NEIClientUtils.translate(message, items.size())
+ EnumChatFormatting.RESET);
}
}
}
}
return currenttip;
}
@Override
public boolean handleClick(int mousex, int mousey, int button) {
final ItemPanelGrid panelGrid = ((ItemPanelGrid) this.grid);
if (NEIClientUtils.altKey() && button == 0 && !panelGrid.forceExpand) {
final ItemPanelSlot hoverSlot = grid.getSlotMouseOver(mousex, mousey);
if (hoverSlot != null) {
final MaskMetadata metadata = panelGrid.maskMetadata.get(hoverSlot.slotIndex);
if (metadata != null) {
ItemList.collapsibleItems.setExpanded(metadata.groupIndex, !metadata.extended);
panelGrid.setItems(panelGrid.rawItems);
return true;
}
}
}
return super.handleClick(mousex, mousey, button);
}
}
@@ -46,7 +46,7 @@ public class ItemSorter implements Comparator<ItemStack>, ItemsLoadedCallback {
// optimisations
public HashMap<ItemStack, Integer> ordering = null;
public static void sort(ArrayList<ItemStack> items) {
public static void sort(List<ItemStack> items) {
try {
// items = (ArrayList<ItemStack>)
// items.parallelStream().sorted(instance).collect(Collectors.toList());
+8 -6
View File
@@ -173,11 +173,13 @@ public class ItemsGrid {
invalidSlotMap = new boolean[rows * columns];
perPage = columns * rows;
if (NEIClientConfig.optimizeGuiOverlapComputation()) {
checkGuiOverlap(gui, 0, columns - 2, 1);
checkGuiOverlap(gui, columns - 1, 1, -1);
} else {
checkGuiOverlap(gui, 0, columns, 1);
if (gui != null) {
if (NEIClientConfig.optimizeGuiOverlapComputation()) {
checkGuiOverlap(gui, 0, columns - 2, 1);
checkGuiOverlap(gui, columns - 1, 1, -1);
} else {
checkGuiOverlap(gui, 0, columns, 1);
}
}
if (oldRows != rows || oldColumns != columns || !Arrays.equals(oldSlotMap, invalidSlotMap)) {
@@ -247,7 +249,7 @@ public class ItemsGrid {
return this.gridMask;
}
private void beforeDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
protected void beforeDrawItems(int mousex, int mousey, @Nullable ItemPanelSlot focused) {
final List<Integer> mask = getMask();
@@ -87,7 +87,6 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
public static ItemPanel itemPanel;
public static BookmarkPanel bookmarkPanel;
public static SubsetWidget dropDown;
public static PresetsWidget presetsPanel;
public static SearchField searchField;
public static boolean searchInitFocusedCancellable = false;
protected static int mousePriorX;
@@ -381,12 +380,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
if (visiblity.showBookmarkPanel || gui.guiTop <= 20) visiblity.showSubsetDropdown = false;
if (!visiblity.showBookmarkPanel || gui.guiTop <= 20) visiblity.showPresetsDropdown = false;
if (gui.guiLeft - 4 < 76) visiblity.showWidgets = false;
if (!itemsLoaded) visiblity.showPresetsDropdown = false;
try {
GuiInfo.readLock.lock();
GuiInfo.guiHandlers.forEach(handler -> handler.modifyVisiblity(gui, visiblity));
@@ -409,8 +404,8 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
bookmarkPanel.init();
dropDown = new SubsetWidget();
presetsPanel = new PresetsWidget();
searchField = new SearchField("search");
API.addItemFilter(searchField);
options = new ButtonCycled(3) {
@@ -714,13 +709,7 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
addWidget(options);
addWidget(bookmarksButton);
if (visiblity.showItemPanel) {
if (PresetsWidget.inEditMode()) {
drawWidgets.add(itemPanel);
} else {
addWidget(itemPanel);
}
addWidget(itemPanel);
itemPanel.setVisible();
}
@@ -729,10 +718,6 @@ public class LayoutManager implements IContainerInputHandler, IContainerTooltipH
bookmarkPanel.setVisible();
}
if (visiblity.showPresetsDropdown) {
addWidget(presetsPanel);
}
searchField.setVisible(visiblity.showSearchSection);
if (visiblity.showSearchSection) {
addWidget(searchField);
@@ -11,7 +11,6 @@ import static codechicken.nei.LayoutManager.itemPanel;
import static codechicken.nei.LayoutManager.itemPresenceOverlays;
import static codechicken.nei.LayoutManager.magnet;
import static codechicken.nei.LayoutManager.options;
import static codechicken.nei.LayoutManager.presetsPanel;
import static codechicken.nei.LayoutManager.rain;
import static codechicken.nei.LayoutManager.searchField;
import static codechicken.nei.LayoutManager.timeButtons;
@@ -121,11 +120,6 @@ public class LayoutStyleMinecraft extends LayoutStyle {
dropDown.y = 0;
dropDown.x = (gui.width - gui.xSize) / 2 + gui.xSize - dropDown.w;
presetsPanel.h = 16;
presetsPanel.w = 150;
presetsPanel.y = 2;
presetsPanel.x = (gui.width - gui.xSize) / 2 + gui.xSize - presetsPanel.w;
searchField.h = 20;
if (NEIClientConfig.isSearchWidgetCentered()) {
searchField.w = 150;
@@ -43,6 +43,7 @@ import codechicken.nei.config.GuiHighlightTips;
import codechicken.nei.config.GuiNEIOptionList;
import codechicken.nei.config.GuiOptionList;
import codechicken.nei.config.GuiPanelSettings;
import codechicken.nei.config.OptionButton;
import codechicken.nei.config.OptionCycled;
import codechicken.nei.config.OptionGamemodes;
import codechicken.nei.config.OptionIntegerField;
@@ -52,6 +53,7 @@ import codechicken.nei.config.OptionTextField;
import codechicken.nei.config.OptionToggleButton;
import codechicken.nei.config.OptionToggleButtonBoubs;
import codechicken.nei.config.OptionUtilities;
import codechicken.nei.config.preset.GuiPresetList;
import codechicken.nei.event.NEIConfigsLoadedEvent;
import codechicken.nei.recipe.GuiRecipeTab;
import codechicken.nei.recipe.IRecipeHandler;
@@ -79,6 +81,7 @@ public class NEIClientConfig {
public static final File handlerOrderingFile = new File(configDir, "handlerordering.csv");
public static final File hiddenHandlersFile = new File(configDir, "hiddenhandlers.csv");
public static final File enableAutoFocusFile = new File(configDir, "enableautofocus.cfg");
public static final File collapsibleItemsFile = new File(configDir, "collapsibleitems.cfg");
@Deprecated
public static File bookmarkFile;
@@ -196,7 +199,7 @@ public class NEIClientConfig {
});
tag.getTag("inventory.search.tooltipSearchMode").setComment("Search mode for Tooltips (prefix: #)")
.getIntValue(1);
.getIntValue(0);
API.addOption(new OptionCycled("inventory.search.tooltipSearchMode", 3, true) {
@Override
@@ -207,7 +210,7 @@ public class NEIClientConfig {
});
tag.getTag("inventory.search.identifierSearchMode").setComment("Search mode for identifier (prefix: &)")
.getIntValue(1);
.getIntValue(0);
API.addOption(new OptionCycled("inventory.search.identifierSearchMode", 3, true) {
@Override
@@ -218,7 +221,7 @@ public class NEIClientConfig {
});
tag.getTag("inventory.search.oreDictSearchMode").setComment("Search mode for Tag Names (prefix: $)")
.getIntValue(1);
.getIntValue(0);
API.addOption(new OptionCycled("inventory.search.oreDictSearchMode", 3, true) {
@Override
@@ -229,7 +232,7 @@ public class NEIClientConfig {
});
tag.getTag("inventory.search.subsetsSearchMode").setComment("Search mode for Item Subsets (prefix: %)")
.getIntValue(1);
.getIntValue(2);
API.addOption(new OptionCycled("inventory.search.subsetsSearchMode", 3, true) {
@Override
@@ -252,6 +255,37 @@ public class NEIClientConfig {
tag.getTag("inventory.history.splittingMode").getIntValue(1);
API.addOption(new OptionCycled("inventory.history.splittingMode", 2, true));
tag.getTag("inventory.collapsibleItems.enabled").getBooleanValue(true);
API.addOption(new OptionToggleButton("inventory.collapsibleItems.enabled", true) {
@Override
public boolean onClick(int button) {
LayoutManager.markItemsDirty();
return super.onClick(button);
}
});
tag.getTag("inventory.collapsibleItems.expandedColor")
.setComment("Color of the collapsible item expanded state").getHexValue(0x335555EE);
API.addOption(new OptionIntegerField("inventory.collapsibleItems.expandedColor"));
tag.getTag("inventory.collapsibleItems.collapsedColor")
.setComment("Color of the collapsible item collapsed state").getHexValue(0x335555EE);
API.addOption(new OptionIntegerField("inventory.collapsibleItems.collapsedColor"));
API.addOption(
new OptionButton(
"inventory.collapsibleItems.reloadLabel",
"inventory.collapsibleItems.reloadButton",
"inventory.collapsibleItems.reloadTip") {
@Override
public boolean onClick(int button) {
LayoutManager.markItemsDirty();
return super.onClick(button);
}
});
tag.getTag("inventory.itemIDs").getIntValue(1);
API.addOption(new OptionCycled("inventory.itemIDs", 3, true));
@@ -272,6 +306,8 @@ public class NEIClientConfig {
API.addOption(new OptionOpenGui("world.panels", GuiPanelSettings.class));
API.addOption(new OptionOpenGui("world.presets", GuiPresetList.class));
tag.getTag("inventory.profileRecipes").getBooleanValue(false);
API.addOption(new OptionToggleButton("inventory.profileRecipes", true));
@@ -645,7 +681,7 @@ public class NEIClientConfig {
worldPath = "global";
}
PresetsWidget.loadPresets(worldPath);
PresetsList.setPresetsFile(worldPath);
}
public static boolean isWorldSpecific(String setting) {
@@ -833,6 +869,10 @@ public class NEIClientConfig {
return getBooleanSetting("inventory.cacheItemRendering") && OpenGlHelper.framebufferSupported;
}
public static boolean enableCollapsibleItems() {
return getBooleanSetting("inventory.collapsibleItems.enabled");
}
public static boolean getMagnetMode() {
return enabledActions.contains("magnet");
}
+12 -6
View File
@@ -42,11 +42,14 @@ public abstract class PanelWidget extends Widget {
pagePrev = new Button("Prev") {
public boolean onButtonPress(boolean rightclick) {
if (!rightclick) {
if (rightclick) {
grid.setPage(0);
} else {
grid.shiftPage(-1);
return true;
}
return false;
return true;
}
@Override
@@ -57,11 +60,14 @@ public abstract class PanelWidget extends Widget {
pageNext = new Button("Next") {
public boolean onButtonPress(boolean rightclick) {
if (!rightclick) {
if (rightclick) {
grid.setPage(grid.getNumPages() - 1);
} else {
grid.shiftPage(1);
return true;
}
return false;
return true;
}
@Override
@@ -0,0 +1,295 @@
package codechicken.nei;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.item.ItemStack;
import org.apache.commons.io.IOUtils;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import codechicken.core.CommonUtils;
import codechicken.nei.api.API;
import codechicken.nei.api.IRecipeFilter;
import codechicken.nei.api.IRecipeFilter.IRecipeFilterProvider;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.recipe.IRecipeHandler;
import codechicken.nei.recipe.StackInfo;
import codechicken.nei.util.NBTJson;
public class PresetsList {
public static enum PresetMode {
HIDE,
REMOVE,
GROUP;
}
public static class Preset implements ItemFilter {
public String name = "";
public boolean enabled = true;
public PresetMode mode = PresetMode.HIDE;
public Set<String> items = new HashSet<>();
public static String getIdentifier(ItemStack stack) {
return StackInfo.getItemStackGUID(stack);
}
@Override
public boolean matches(ItemStack item) {
return items.contains(Preset.getIdentifier(item));
}
public Preset copy() {
Preset preset = new Preset();
preset.name = name;
preset.enabled = enabled;
preset.mode = mode;
preset.items = new HashSet<>(items);
return preset;
}
}
protected static class RecipesFilter implements IRecipeFilterProvider, IRecipeFilter {
public Set<String> cache;
public IRecipeFilter getFilter() {
if (cache == null) {
cache = PresetsList.presets.stream().filter(p -> p.enabled && p.mode == PresetMode.REMOVE)
.flatMap(p -> p.items.stream()).collect(Collectors.toSet());
}
return cache.isEmpty() ? null : this;
}
@Override
public boolean matches(IRecipeHandler handler, List<PositionedStack> ingredients, PositionedStack result,
List<PositionedStack> others) {
if (matchPositionedStack(ingredients, false)) {
return false;
}
if (result != null && matchPositionedStack(result)) {
return true;
}
if (!others.isEmpty() && matchPositionedStack(others, true)) {
return true;
}
return result == null && others.isEmpty();
}
private boolean matchPositionedStack(List<PositionedStack> items, boolean dir) {
for (PositionedStack pStack : items) {
if (matchPositionedStack(pStack) == dir) {
return true;
}
}
return false;
}
private boolean matchPositionedStack(PositionedStack pStack) {
for (ItemStack stack : pStack.items) {
if (!cache.contains(Preset.getIdentifier(stack))) {
return true;
}
}
return false;
}
}
protected static class ItemPanelFilter implements ItemFilterProvider, ItemFilter {
public Set<String> cache;
public ItemFilter getFilter() {
if (cache == null) {
cache = PresetsList.presets.stream()
.filter(p -> p.enabled && (p.mode == PresetMode.HIDE || p.mode == PresetMode.REMOVE))
.flatMap(p -> p.items.stream()).collect(Collectors.toSet());
}
return cache.isEmpty() ? null : this;
}
@Override
public boolean matches(ItemStack stack) {
return !cache.contains(Preset.getIdentifier(stack));
}
}
public static final List<Preset> presets = new ArrayList<>();
protected static File presetsFile;
protected static RecipesFilter recipeFilter = new RecipesFilter();
protected static ItemPanelFilter itemFilter = new ItemPanelFilter();
static {
API.addItemFilter(itemFilter);
API.addRecipeFilter(recipeFilter);
ItemList.loadCallbacks.add(PresetsList::itemsLoaded);
}
public static ItemFilter getItemFilter() {
return itemFilter.getFilter();
}
public static void itemsLoaded() {
recipeFilter.cache = null;
itemFilter.cache = null;
ItemList.collapsibleItems.reload();
}
public static void setPresetsFile(String worldPath) {
final File dir = new File(CommonUtils.getMinecraftDir(), "saves/NEI/" + worldPath);
if (!dir.exists()) {
dir.mkdirs();
}
presetsFile = new File(dir, "presets.ini");
if (!presetsFile.exists()) {
final File globalPresets = new File(CommonUtils.getMinecraftDir(), "saves/NEI/global/presets.ini");
final File configPresets = new File(NEIClientConfig.configDir, "presets.ini");
final File defaultBookmarks = configPresets.exists() ? configPresets : globalPresets;
if (defaultBookmarks.exists()) {
try {
presetsFile.createNewFile();
InputStream src = new FileInputStream(defaultBookmarks);
OutputStream dst = new FileOutputStream(presetsFile);
IOUtils.copy(src, dst);
src.close();
dst.close();
} catch (IOException e) {}
}
}
loadPresets();
}
protected static void loadPresets() {
if (presetsFile == null || !presetsFile.exists()) {
return;
}
List<String> itemStrings;
try (FileInputStream reader = new FileInputStream(presetsFile)) {
NEIClientConfig.logger.info("Loading presets from file {}", presetsFile);
itemStrings = IOUtils.readLines(reader, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Failed to load presets from file {}", presetsFile, e);
return;
}
JsonParser parser = new JsonParser();
Preset preset = new Preset();
presets.clear();
for (String itemStr : itemStrings) {
try {
if (itemStr.isEmpty()) {
itemStr = "; {}";
}
if (itemStr.startsWith("; ")) {
JsonObject settings = parser.parse(itemStr.substring(2)).getAsJsonObject();
if (!preset.items.isEmpty()) {
// do not create empty namespaces
presets.add(preset);
preset = new Preset();
}
if (settings.get("name") != null) {
preset.name = settings.get("name").getAsString();
}
if (settings.get("enabled") != null) {
preset.enabled = settings.get("enabled").getAsBoolean();
}
if (settings.get("mode") != null) {
preset.mode = PresetMode.valueOf(settings.get("mode").getAsString());
}
} else {
preset.items.add(itemStr);
}
} catch (IllegalArgumentException | JsonSyntaxException | IllegalStateException e) {
NEIClientConfig.logger.error("Failed to load presets ItemStack from json string:\n{}", itemStr);
}
}
if (!preset.items.isEmpty()) {
presets.add(preset);
}
itemsLoaded();
}
public static void savePresets() {
if (presetsFile == null) {
return;
}
List<String> strings = new ArrayList<>();
for (Preset preset : presets) {
JsonObject settings = new JsonObject();
settings.add("name", new JsonPrimitive(preset.name));
settings.add("enabled", new JsonPrimitive(preset.enabled));
settings.add("mode", new JsonPrimitive(preset.mode.toString()));
strings.add("; " + NBTJson.toJson(settings));
strings.addAll(preset.items);
}
try (FileOutputStream output = new FileOutputStream(presetsFile)) {
IOUtils.writeLines(strings, "\n", output, StandardCharsets.UTF_8);
} catch (IOException e) {
NEIClientConfig.logger.error("Filed to save presets list to file {}", presetsFile, e);
}
itemsLoaded();
}
}
File diff suppressed because it is too large. Load diff
@@ -1,8 +1,8 @@
package codechicken.nei;
import net.minecraft.client.Minecraft;
import net.minecraft.util.EnumChatFormatting;
import codechicken.nei.SearchField.GuiSearchField;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.util.TextHistory;
@@ -17,8 +17,7 @@ public abstract class RecipeSearchField extends TextField {
@Override
protected void initInternalTextField() {
field = new FormattedTextField(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0);
((FormattedTextField) field).setFormatter(new SearchTextFormatter(SearchField.searchParser));
field = new GuiSearchField();
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
@@ -60,7 +59,7 @@ public abstract class RecipeSearchField extends TextField {
}
public ItemFilter getFilter() {
return SearchField.getFilter(text());
return ((GuiSearchField) field).getFilter();
}
@Override
+56 -13
View File
@@ -1,7 +1,5 @@
package codechicken.nei;
import static codechicken.nei.NEIClientConfig.world;
import java.util.LinkedList;
import java.util.List;
import java.util.function.Function;
@@ -18,7 +16,6 @@ import codechicken.lib.gui.GuiDraw;
import codechicken.nei.ItemList.NothingItemFilter;
import codechicken.nei.SearchTokenParser.ISearchParserProvider;
import codechicken.nei.SearchTokenParser.SearchMode;
import codechicken.nei.api.API;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemFilter.ItemFilterProvider;
import codechicken.nei.recipe.StackInfo;
@@ -91,28 +88,50 @@ public class SearchField extends TextField implements ItemFilterProvider {
}
}
public static class GuiSearchField extends FormattedTextField {
protected final SearchTokenParser searchParser;
public GuiSearchField() {
this(SearchField.searchParser);
}
public GuiSearchField(SearchTokenParser searchParser) {
super(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0);
this.searchParser = searchParser;
setFormatter(new SearchTextFormatter(searchParser));
}
public ItemFilter getFilter() {
return getFilter(getText());
}
public ItemFilter getFilter(String filterText) {
return this.searchParser.getFilter(filterText);
}
}
@Deprecated
public static List<ISearchProvider> searchProviders = new LinkedList<>();
public static SearchTokenParser searchParser = new SearchTokenParser();
public static final SearchTokenParser searchParser = new SearchTokenParser();
private static final TextHistory history = new TextHistory();
private boolean isVisible = true;
private long lastclicktime;
public SearchField(String ident) {
super(ident);
API.addItemFilter(this);
}
@Override
protected void initInternalTextField() {
field = new FormattedTextField(Minecraft.getMinecraft().fontRenderer, 0, 0, 0, 0);
((FormattedTextField) field).setFormatter(new SearchTextFormatter(SearchField.searchParser));
field = new GuiSearchField();
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
public static boolean searchInventories() {
return world.nbt.getBoolean("searchinventories");
return NEIClientConfig.world.nbt.getBoolean("searchinventories");
}
public boolean isVisible() {
@@ -137,10 +156,34 @@ public class SearchField extends TextField implements ItemFilterProvider {
super.draw(mousex, mousey);
if (searchInventories()) {
GuiDraw.drawGradientRect(x - 1, y - 1, 1, h + 2, 0xFFFFFF00, 0xFFC0B000); // Left
GuiDraw.drawGradientRect(x - 1, y - 1, w + 2, 1, 0xFFFFFF00, 0xFFC0B000); // Top
GuiDraw.drawGradientRect(x + w, y - 1, 1, h + 2, 0xFFFFFF00, 0xFFC0B000); // Left
GuiDraw.drawGradientRect(x - 1, y + h, w + 2, 1, 0xFFFFFF00, 0xFFC0B000); // Bottom
GuiDraw.drawGradientRect(
field.xPosition - 1,
field.yPosition - 1,
1,
field.height + 2,
0xFFFFFF00,
0xFFC0B000); // Left
GuiDraw.drawGradientRect(
field.xPosition - 1,
field.yPosition - 1,
field.width + 2,
1,
0xFFFFFF00,
0xFFC0B000); // Top
GuiDraw.drawGradientRect(
field.xPosition + field.width,
field.yPosition - 1,
1,
field.height + 2,
0xFFFFFF00,
0xFFC0B000); // Left
GuiDraw.drawGradientRect(
field.xPosition - 1,
field.yPosition + field.height,
field.width + 2,
1,
0xFFFFFF00,
0xFFC0B000); // Bottom
}
}
@@ -268,7 +311,7 @@ public class SearchField extends TextField implements ItemFilterProvider {
@Override
public ItemFilter getFilter() {
return getFilter(text());
return ((GuiSearchField) field).getFilter();
}
public static ItemFilter getFilter(String filterText) {
@@ -15,10 +15,6 @@ public class VisiblityData {
* Subset dropdown
*/
public boolean showSubsetDropdown = true;
/**
* Presets dropdown
*/
public boolean showPresetsDropdown = true;
/**
* Item and search section
*/
@@ -44,7 +40,6 @@ public class VisiblityData {
public void translateDependancies() {
if (!showNEI) showWidgets = false;
if (!showWidgets) showItemSection = showUtilityButtons = false;
if (!showItemSection)
showBookmarkPanel = showSubsetDropdown = showPresetsDropdown = showSearchSection = showItemPanel = false;
if (!showItemSection) showBookmarkPanel = showSubsetDropdown = showSearchSection = showItemPanel = false;
}
}
@@ -113,8 +113,13 @@ public class GuiItemSorter extends GuiOptionPane {
if (nslot != list.indexOf(dragged.e)) {
list.remove(dragged.e);
list.add(nslot, dragged.e);
opt.getTag().setValue(ItemSorter.getSaveString(list));
if (opt.activeTag() == opt.getTag()) ItemSorter.list = new ArrayList<>(list);
LayoutManager.markItemsDirty();
if (opt.activeTag() == opt.getTag()) {
ItemSorter.list = new ArrayList<>(list);
}
}
}
}
@@ -80,7 +80,7 @@ public class OptionTextField extends Option {
public List<String> handleTooltip(int mousex, int mousey, List<String> currenttip) {
if (new Rectangle4i(10, 0, textField.x - 10, 20).contains(mousex, mousey)) {
String tip = translateN(name + ".tip");
if (!tip.equals(name + ".tip")) currenttip.add(tip);
if (!tip.equals(namespaced(name + ".tip"))) currenttip.add(tip);
}
return currenttip;
}
@@ -0,0 +1,53 @@
package codechicken.nei.config.preset;
import static codechicken.lib.gui.GuiDraw.drawStringC;
import org.lwjgl.opengl.GL11;
import codechicken.nei.Button;
import codechicken.nei.LayoutManager;
public abstract class CheckboxButton extends Button {
protected boolean checked = false;
public CheckboxButton(String s) {
super(s);
}
public void setChecked(boolean checked) {
this.checked = checked;
this.onChange();
}
public boolean isChecked() {
return this.checked;
}
@Override
public void draw(int mousex, int mousey) {
GL11.glDisable(GL11.GL_LIGHTING);
GL11.glColor4f(1, 1, 1, 1);
int tex;
if ((this.state & 0x3) == 2) {
tex = 0;
} else if ((this.state & 0x4) == 0 && contains(mousex, mousey) || (this.state & 0x3) == 1) {
tex = 2;
} else {
tex = 1;
}
int colour = tex == 2 ? 0xffffa0 : tex == 0 ? 0x601010 : 0xe0e0e0;
LayoutManager.drawButtonBackground(x, y, w, h, true, isChecked() ? 0 : tex);
drawStringC(getRenderLabel(), x + w / 2, y + (h - 8) / 2, colour);
}
public boolean onButtonPress(boolean rightclick) {
this.setChecked(!isChecked());
return true;
}
protected abstract void onChange();
}
@@ -0,0 +1,239 @@
package codechicken.nei.config.preset;
import static codechicken.lib.gui.GuiDraw.getStringWidth;
import java.awt.Rectangle;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiScreen;
import org.lwjgl.opengl.GL11;
import codechicken.core.gui.GuiCCButton;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.config.GuiOptionPane;
import codechicken.nei.config.Option;
public class GuiPresetList extends GuiOptionPane {
private final Option opt;
protected final static int SLOT_HEIGHT = 24;
protected final static int BUTTON_HEIGHT = 20;
protected GuiCCButton createButton;
protected int sortingItemIndex = -1;
public GuiPresetList(Option opt) {
this.opt = opt;
this.createButton = new GuiCCButton(0, 2, 0, 16, NEIClientUtils.translate("presets.new"))
.setActionCommand("create");
}
@Override
public void initGui() {
super.initGui();
this.createButton.width = getStringWidth(this.createButton.text) + 15;
this.createButton.x = width - this.createButton.width - 15;
}
@Override
public void addWidgets() {
super.addWidgets();
add(this.createButton);
}
@Override
public void actionPerformed(String ident, Object... params) {
super.actionPerformed(ident, params);
if (ident.equals("create")) {
cretePreset();
}
}
protected void mouseClicked(int x, int y, int button) {
super.mouseClicked(x, y, button);
}
@Override
protected void mouseMovedOrUp(int x, int y, int button) {
super.mouseMovedOrUp(x, y, button);
if (sortingItemIndex >= 0) {
PresetsList.savePresets();
} else if (button == 0) {
int slot = getSlotMouseOver(x, y);
if (slot != -1) {
Rectangle w = pane.windowBounds();
int mx = x - w.x;
if (mx <= BUTTON_HEIGHT) {
Preset preset = PresetsList.presets.get(slot);
preset.enabled = !preset.enabled;
PresetsList.savePresets();
} else if (mx >= 26 && mx <= w.width - 26 * 2) {
openPreset(slot);
} else if (mx >= w.width - BUTTON_HEIGHT) {
PresetsList.presets.remove(slot);
PresetsList.savePresets();
}
}
}
sortingItemIndex = -1;
}
@Override
protected void mouseClickMove(int x, int y, int button, long time) {
super.mouseClickMove(x, y, button, time);
if (sortingItemIndex == -1) {
Rectangle w = pane.windowBounds();
int mx = x - w.x;
if (mx >= 26 && mx <= w.width - 26 * 2) {
sortingItemIndex = getSlotMouseOver(x, y);
} else {
sortingItemIndex = -2;
}
} else if (sortingItemIndex >= 0) {
Rectangle w = pane.windowBounds();
if (y >= w.y && y <= w.y + w.height) {
int my = y + pane.scrolledPixels() - w.y;
int slot = my / SLOT_HEIGHT;
if (my % SLOT_HEIGHT < BUTTON_HEIGHT && slot < PresetsList.presets.size()
&& slot != -1
&& slot != sortingItemIndex) {
PresetsList.presets.add(slot, PresetsList.presets.remove(sortingItemIndex));
sortingItemIndex = slot;
}
}
}
}
protected int getSlotMouseOver(int x, int y) {
Rectangle w = pane.windowBounds();
if (x >= w.x && x <= w.x + w.width && y >= w.y && y <= w.y + w.height) {
int my = y + pane.scrolledPixels() - w.y;
int slot = my / SLOT_HEIGHT;
if (my % SLOT_HEIGHT < BUTTON_HEIGHT && slot < PresetsList.presets.size()) {
return slot;
}
}
return -1;
}
protected void cretePreset() {
Minecraft.getMinecraft().displayGuiScreen(new GuiPresetSettings(this, -1));
}
protected void openPreset(int slot) {
Minecraft.getMinecraft().displayGuiScreen(new GuiPresetSettings(this, slot));
}
@Override
public int contentHeight() {
return PresetsList.presets.size() * SLOT_HEIGHT;
}
@Override
public void drawContent(int mx, int my, float frame) {
int scrolled = pane.scrolledPixels();
Rectangle w = pane.windowBounds();
int y = 0;
for (int slot = 0; slot < PresetsList.presets.size(); ++slot) {
if (y + SLOT_HEIGHT > scrolled && y < scrolled + w.height) {
if (sortingItemIndex != slot) {
drawSlot(w, slot, w.x, w.y + y - scrolled, mx, my - y);
}
}
y += SLOT_HEIGHT;
}
if (sortingItemIndex >= 0) {
drawSlot(w, sortingItemIndex, w.x, w.y + my - scrolled - BUTTON_HEIGHT / 2, mx, my - y);
}
}
protected void drawSlot(Rectangle w, int slot, int x, int y, int mx, int my) {
final Rectangle4i delete = new Rectangle4i(x + w.width - BUTTON_HEIGHT, y, BUTTON_HEIGHT, BUTTON_HEIGHT);
final Rectangle4i enabled = new Rectangle4i(x, y, BUTTON_HEIGHT, BUTTON_HEIGHT);
final Rectangle4i option = new Rectangle4i(x + 26, y, w.width - 26 * 2, BUTTON_HEIGHT);
final int enabledState = y + my >= w.y && y + my <= w.y + w.height && enabled.contains(x + mx, y + my) ? 2 : 1;
final int optionState = y + my >= w.y && y + my <= w.y + w.height && option.contains(x + mx, y + my) ? 2 : 1;
final int deleteState = y + my >= w.y && y + my <= w.y + w.height && delete.contains(x + mx, y + my) ? 2 : 1;
final Preset preset = PresetsList.presets.get(slot);
final String displayName = preset.name;
final String modeName;
switch (preset.mode) {
case HIDE:
modeName = NEIClientUtils.translate("presets.mode.hide.char");
break;
case REMOVE:
modeName = NEIClientUtils.translate("presets.mode.remove.char");
break;
case GROUP:
modeName = NEIClientUtils.translate("presets.mode.group.char");
break;
default:
modeName = "?";
break;
}
// enabled icon
GL11.glColor4f(1, 1, 1, 1);
LayoutManager.drawButtonBackground(
enabled.x,
enabled.y,
enabled.w,
enabled.h,
true,
preset.enabled ? 0 : enabledState);
GuiDraw.drawString("✔", enabled.x + 7, enabled.y + 6, enabledState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
// preset name
GL11.glColor4f(1, 1, 1, 1);
LayoutManager.drawButtonBackground(option.x, option.y, option.w, option.h, true, optionState);
GuiDraw.drawString("⋮⋮", option.x + 4, option.y + 5, optionState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
GuiDraw.drawString(
NEIClientUtils.cropText(this.fontRendererObj, modeName + ": " + displayName, option.w - 16),
option.x + 6 + 4,
option.y + 6,
optionState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
// remove icon
GL11.glColor4f(1, 1, 1, 1);
LayoutManager.drawButtonBackground(delete.x, delete.y, delete.w, delete.h, true, deleteState);
GuiDraw.drawString("✕", delete.x + 7, delete.y + 6, deleteState == 2 ? 0xFFFFFFA0 : 0xFFE0E0E0);
}
@Override
public GuiScreen getParentScreen() {
return opt.slot.getGui();
}
@Override
public String getTitle() {
return opt.translateN(opt.name);
}
}
@@ -0,0 +1,228 @@
package codechicken.nei.config.preset;
import java.util.LinkedList;
import java.util.List;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.Gui;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.renderer.Tessellator;
import org.lwjgl.opengl.GL11;
import org.lwjgl.util.Rectangle;
import codechicken.core.gui.GuiScreenWidget;
import codechicken.nei.Button;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.config.OptionScrollPane;
import codechicken.nei.guihook.GuiContainerManager;
public class GuiPresetSettings extends GuiScreenWidget {
protected final Preset preset;
protected final GuiScreen parent;
protected final int slotIndex;
public int marginleft;
public int margintop;
public int marginright;
public int marginbottom;
protected LeftPanel leftPanel;
protected RightPanel rightPanel;
protected Button backButton;
protected Button saveButton;
public GuiPresetSettings(GuiScreen parent, int slotIndex) {
this.parent = parent;
this.setMargins(6, 20, 6, 30);
this.slotIndex = slotIndex;
if (slotIndex == -1) {
preset = new Preset();
} else {
preset = PresetsList.presets.get(slotIndex).copy();
}
leftPanel = new LeftPanel(preset) {
@Override
protected void onItemsChanges() {
leftPanel.grid.restartFilter();
}
};
rightPanel = new RightPanel(preset, slotIndex) {
@Override
protected void onItemsChanges() {
leftPanel.grid.restartFilter();
}
};
backButton = new Button(NEIClientUtils.translate("options.back")) {
public boolean onButtonPress(boolean rightclick) {
Minecraft.getMinecraft().displayGuiScreen(parent);
return true;
}
};
saveButton = new Button(NEIClientUtils.translate("options.save")) {
public boolean onButtonPress(boolean rightclick) {
if (state == 0) {
if (slotIndex == -1) {
PresetsList.presets.add(preset);
} else {
PresetsList.presets.set(slotIndex, preset);
}
PresetsList.savePresets();
Minecraft.getMinecraft().displayGuiScreen(parent);
return true;
}
return false;
}
};
add(this.leftPanel);
add(this.rightPanel);
}
protected void setMargins(int left, int top, int right, int bottom) {
this.marginleft = left;
this.margintop = top;
this.marginright = right;
this.marginbottom = bottom;
}
protected Rectangle windowBounds() {
return new Rectangle(
this.marginleft,
this.margintop,
this.width - this.marginleft - this.marginright,
this.height - this.margintop - this.marginbottom);
}
@Override
public boolean doesGuiPauseGame() {
return true;
}
@Override
public void updateScreen() {
final Rectangle bounds = windowBounds();
final int panelWidth = bounds.getWidth() * 2 / 5;
this.leftPanel.setSize(bounds.getX(), bounds.getY() + 4, panelWidth, bounds.getHeight() - 6);
this.rightPanel.setSize(
bounds.getX() + bounds.getWidth() - panelWidth,
bounds.getY() + 4,
panelWidth,
bounds.getHeight() - 6);
final int w = Math.min(200, width - 40);
backButton.w = w / 2 - 3;
backButton.h = 20;
backButton.x = (width - w) / 2;
backButton.y = height - 25;
saveButton.state = preset.name.isEmpty() || preset.mode == null || preset.items.isEmpty() ? 2 : 0;
saveButton.w = w / 2 - 3;
saveButton.h = 20;
saveButton.x = width / 2 + 3;
saveButton.y = height - 25;
super.updateScreen();
}
@Override
public void resize() {
this.guiLeft = this.guiTop = 0;
}
@Override
public void drawScreen(int mousex, int mousey, float f) {
Rectangle bounds = windowBounds();
drawDefaultBackground();
drawOverlay(bounds.getY(), bounds.getHeight(), width, zLevel);
drawCenteredString(
Minecraft.getMinecraft().fontRenderer,
NEIClientUtils.translate(this.slotIndex == -1 ? "presets.create" : "presets.update"),
width / 2,
6,
-1);
backButton.draw(mousex, mousey);
saveButton.draw(mousex, mousey);
super.drawScreen(mousex, mousey, f);
List<String> tooltip = new LinkedList<>();
tooltip = leftPanel.handleTooltip(mousex, mousey, tooltip);
tooltip = rightPanel.handleTooltip(mousex, mousey, tooltip);
GuiContainerManager.drawPagedTooltip(Minecraft.getMinecraft().fontRenderer, mousex + 12, mousey - 12, tooltip);
}
@Override
protected void mouseClicked(int x, int y, int button) {
super.mouseClicked(x, y, button);
if (backButton.contains(x, y)) {
backButton.handleClick(x, y, button);
}
if (saveButton.contains(x, y)) {
saveButton.handleClick(x, y, button);
}
}
public static void drawOverlay(int y, int height, int screenwidth, float zLevel) {
OptionScrollPane.drawOverlayTex(0, 0, screenwidth, y, zLevel);
OptionScrollPane.drawOverlayTex(0, y + height, screenwidth, screenwidth - y - height, zLevel);
OptionScrollPane.drawOverlayGrad(0, screenwidth, y, y + 4, zLevel);
OptionScrollPane.drawOverlayGrad(0, screenwidth, y + height, y + height - 4, zLevel);
}
public static void drawOverlayTex(int x, int y, int w, int h, float zLevel) {
GL11.glColor4f(1, 1, 1, 1);
Minecraft.getMinecraft().renderEngine.bindTexture(Gui.optionsBackground);
Tessellator t = Tessellator.instance;
t.startDrawingQuads();
t.addVertexWithUV(x, y, zLevel, 0, 0);
t.addVertexWithUV(x, y + h, zLevel, 0, h / 16D);
t.addVertexWithUV(x + w, y + h, zLevel, w / 16D, h / 16D);
t.addVertexWithUV(x + w, y, zLevel, w / 16D, 0);
t.draw();
}
public static void drawOverlayGrad(int x1, int x2, int y1, int y2, float zLevel) {
GL11.glDisable(GL11.GL_TEXTURE_2D);
GL11.glDisable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glShadeModel(GL11.GL_SMOOTH);
Tessellator t = Tessellator.instance;
t.startDrawingQuads();
t.setColorRGBA_I(0, 255);
t.addVertex(x2, y1, zLevel);
t.addVertex(x1, y1, zLevel);
t.setColorRGBA_I(0, 0);
t.addVertex(x1, y2, zLevel);
t.addVertex(x2, y2, zLevel);
t.draw();
GL11.glDisable(GL11.GL_BLEND);
GL11.glEnable(GL11.GL_CULL_FACE);
GL11.glEnable(GL11.GL_TEXTURE_2D);
}
}
@@ -0,0 +1,327 @@
package codechicken.nei.config.preset;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.item.ItemStack;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.core.gui.GuiWidget;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemList.AllMultiItemFilter;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemsGrid;
import codechicken.nei.Label;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.PresetsList.PresetMode;
import codechicken.nei.TextField;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
public class LeftPanel extends GuiWidget {
protected static class MouseSelection {
public int startX = -1;
public int startY = -1;
public int startIndex = -1;
public int endIndex = -1;
public Set<ItemStack> items = new HashSet<>();
public MouseSelection(int slotIndex, Rectangle4i rec) {
endIndex = slotIndex;
startIndex = slotIndex;
startX = rec.x;
startY = rec.y;
}
}
protected static final int INPUT_HEIGHT = 20;
public final PresetItemsGrid grid = new PresetItemsGrid() {
@Override
protected ItemFilter getFilter() {
Set<String> identifiers = preset.items;
return new AllMultiItemFilter(
item -> !ItemInfo.hiddenItems.contains(item),
item -> identifiers.contains(Preset.getIdentifier(item)));
}
@Override
protected boolean isSelected(ItemStack stack) {
return mouseSelection != null && mouseSelection.items.contains(stack);
}
};
protected Label nameLabel = new Label(NEIClientUtils.translate("presets.name"), false);
protected TextField nameField = new TextField("name") {
@Override
public void onTextChange(String oldText) {
preset.name = text();
}
};
protected Label modeLabel = new Label(NEIClientUtils.translate("presets.mode"), false);
protected CheckboxButton modeHide;
protected CheckboxButton modeRemove;
protected CheckboxButton modeGroup;
protected CheckboxButton enabledButton;
protected final Preset preset;
protected MouseSelection mouseSelection;
public LeftPanel(Preset preset) {
super(1, 0, 2, 2);
this.preset = preset;
nameField.setText(preset.name);
modeHide = new CheckboxButton(NEIClientUtils.translate("presets.mode.hide")) {
@Override
public boolean isChecked() {
return preset.mode == PresetMode.HIDE;
}
@Override
protected void onChange() {
preset.mode = this.checked ? PresetMode.HIDE : null;
}
};
modeRemove = new CheckboxButton(NEIClientUtils.translate("presets.mode.remove")) {
@Override
public boolean isChecked() {
return preset.mode == PresetMode.REMOVE;
}
@Override
protected void onChange() {
preset.mode = this.checked ? PresetMode.REMOVE : null;
}
};
modeGroup = new CheckboxButton(NEIClientUtils.translate("presets.mode.group")) {
@Override
public boolean isChecked() {
return preset.mode == PresetMode.GROUP;
}
@Override
protected void onChange() {
preset.mode = this.checked ? PresetMode.GROUP : null;
}
};
enabledButton = new CheckboxButton(NEIClientUtils.translate("presets.enabled")) {
@Override
public boolean isChecked() {
return preset.enabled;
}
@Override
protected void onChange() {
preset.enabled = this.checked;
}
};
grid.restartFilter();
}
public void mouseClicked(int x, int y, int button) {
grid.mouseClicked(x, y, button);
if (modeHide.contains(x, y)) {
modeHide.handleClick(x, y, button);
}
if (modeRemove.contains(x, y)) {
modeRemove.handleClick(x, y, button);
}
if (modeGroup.contains(x, y)) {
modeGroup.handleClick(x, y, button);
}
if (enabledButton.contains(x, y)) {
enabledButton.handleClick(x, y, button);
}
if (nameField.contains(x, y)) {
nameField.handleClick(x, y, button);
} else {
nameField.onGuiClick(x, y);
}
if (mouseSelection == null && button == 0) {
ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null) {
mouseSelection = new MouseSelection(slot.slotIndex, grid.getItemRect(slot.slotIndex));
}
}
}
protected void onItemsChanges() {}
public void mouseMovedOrUp(int x, int y, int button) {
nameField.mouseUp(x, y, button);
if (mouseSelection != null && button == 0) {
ItemPanelSlot hoverSlot = grid.getSlotMouseOver(x, y);
if (hoverSlot != null && hoverSlot.slotIndex == mouseSelection.startIndex) {
preset.items.remove(Preset.getIdentifier(hoverSlot.item));
} else if (!mouseSelection.items.isEmpty()) {
for (ItemStack stack : mouseSelection.items) {
preset.items.remove(Preset.getIdentifier(stack));
}
}
mouseSelection = null;
onItemsChanges();
}
}
public void mouseDragged(int x, int y, int button, long time) {
nameField.mouseDragged(x, y, button, time);
if (mouseSelection != null && button == 0) {
final ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null && slot.slotIndex != mouseSelection.endIndex) {
mouseSelection.endIndex = slot.slotIndex;
mouseSelection.items.clear();
final Rectangle4i rec = grid.getItemRect(slot.slotIndex);
final Rectangle4i sel = new Rectangle4i(
Math.min(rec.x, mouseSelection.startX),
Math.min(rec.y, mouseSelection.startY),
Math.max(rec.x, mouseSelection.startX) - Math.min(rec.x, mouseSelection.startX),
Math.max(rec.y, mouseSelection.startY) - Math.min(rec.y, mouseSelection.startY));
for (int ix = sel.x; ix <= sel.x + sel.w; ix += ItemsGrid.SLOT_SIZE) {
for (int iy = sel.y; iy <= sel.y + sel.h; iy += ItemsGrid.SLOT_SIZE) {
ItemPanelSlot over = grid.getSlotMouseOver(ix, iy);
if (over != null) {
mouseSelection.items.add(over.item);
}
}
}
}
}
}
public void update() {
int CHECKBOX_WIDTH = (this.width - 12) / 3;
nameLabel.x = this.x + 2;
nameLabel.y = this.y + 4;
nameLabel.w = this.width;
nameLabel.h = 10;
nameField.x = this.x;
nameField.y = nameLabel.y + nameLabel.h;
nameField.w = this.width - CHECKBOX_WIDTH - 6;
nameField.h = INPUT_HEIGHT;
enabledButton.x = nameField.x + nameField.w + 6;
enabledButton.y = nameField.y;
enabledButton.w = CHECKBOX_WIDTH;
enabledButton.h = INPUT_HEIGHT;
modeLabel.x = this.x + 2;
modeLabel.y = nameField.y + nameField.h + 6;
modeLabel.w = this.width;
modeLabel.h = 10;
modeHide.w = modeRemove.w = modeGroup.w = CHECKBOX_WIDTH;
modeHide.h = modeRemove.h = modeGroup.h = INPUT_HEIGHT;
modeHide.y = modeRemove.y = modeGroup.y = modeLabel.y + modeLabel.h;
modeHide.x = this.x + 1;
modeRemove.x = modeHide.x + modeHide.w + 6;
modeGroup.x = modeRemove.x + modeRemove.w + 6;
grid.setGridSize(
this.x + 1,
modeHide.y + modeHide.h + 2,
this.width - 2,
this.height - (modeHide.y + modeHide.h + 2));
grid.refresh(null);
}
public void draw(int mousex, int mousey, float frame) {
nameLabel.draw(mousex, mousey);
nameField.draw(mousex, mousey);
modeLabel.draw(mousex, mousey);
modeHide.draw(mousex, mousey);
modeRemove.draw(mousex, mousey);
modeGroup.draw(mousex, mousey);
enabledButton.draw(mousex, mousey);
RenderHelper.enableGUIStandardItemLighting();
GL11.glPushMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
grid.draw(mousex, mousey);
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
RenderHelper.enableStandardItemLighting();
}
public List<String> handleTooltip(int mousex, int mousey, List<String> tooltip) {
ItemPanelSlot over = grid.getSlotMouseOver(mousex, mousey);
if (over != null) {
tooltip = GuiContainerManager.itemDisplayNameMultiline(over.item, null, true);
synchronized (GuiContainerManager.tooltipHandlers) {
for (IContainerTooltipHandler handler : GuiContainerManager.tooltipHandlers) {
tooltip = handler.handleItemTooltip(null, over.item, mousex, mousey, tooltip);
}
}
if (tooltip.size() > 0) {
tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
}
} else if (modeHide.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.hide.tip"));
} else if (modeRemove.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.remove.tip"));
} else if (modeGroup.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.mode.group.tip"));
}
return tooltip;
}
public void keyTyped(char c, int keycode) {
nameField.handleKeyPress(keycode, c);
}
}
@@ -0,0 +1,167 @@
package codechicken.nei.config.preset;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import javax.annotation.Nullable;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.item.ItemStack;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.Button;
import codechicken.nei.ItemList;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemSorter;
import codechicken.nei.ItemsGrid;
import codechicken.nei.Label;
import codechicken.nei.RestartableTask;
import codechicken.nei.api.ItemFilter;
public abstract class PresetItemsGrid extends ItemsGrid {
protected static final int BUTTON_SIZE = 16;
public Button pagePrev;
public Label pageLabel;
public Button pageNext;
protected ArrayList<ItemStack> newItems;
protected final RestartableTask updateFilter = new RestartableTask("NEI Presets Item Filtering") {
@Override
public void execute() {
ArrayList<ItemStack> filtered;
ItemFilter filter = getFilter();
try {
filtered = ItemList.forkJoinPool.submit(
() -> ItemList.items.parallelStream().filter(filter::matches)
.collect(Collectors.toCollection(ArrayList::new)))
.get();
} catch (InterruptedException | ExecutionException e) {
filtered = new ArrayList<>();
e.printStackTrace();
stop();
}
if (interrupted()) return;
ItemSorter.sort(filtered);
if (interrupted()) return;
updateItemList(filtered);
}
};
public PresetItemsGrid() {
pageLabel = new Label("0/0", true);
pagePrev = new Button("<") {
public boolean onButtonPress(boolean rightclick) {
if (rightclick) {
setPage(0);
} else {
shiftPage(-1);
}
return true;
}
};
pageNext = new Button(">") {
public boolean onButtonPress(boolean rightclick) {
if (rightclick) {
setPage(getNumPages() - 1);
} else {
shiftPage(1);
}
return true;
}
};
}
protected String getLabelText() {
return String.format("%d/%d", getPage(), Math.max(1, getNumPages()));
}
@Override
public void setGridSize(int mleft, int mtop, int w, int h) {
pageLabel.text = getLabelText();
pagePrev.w = pageNext.w = BUTTON_SIZE;
pagePrev.h = pageNext.h = BUTTON_SIZE;
pagePrev.y = pageNext.y = mtop;
pagePrev.x = mleft;
pageNext.x = mleft + w - pageNext.w;
pageLabel.x = mleft + w / 2;
pageLabel.y = pagePrev.y + 5;
super.setGridSize(mleft, mtop + BUTTON_SIZE + 2, w, h - BUTTON_SIZE - 4);
}
@Override
public void draw(int mousex, int mousey) {
pagePrev.draw(mousex, mousey);
pageNext.draw(mousex, mousey);
pageLabel.draw(mousex, mousey);
super.draw(mousex, mousey);
}
public void mouseClicked(int x, int y, int button) {
if (pagePrev.contains(x, y)) {
pagePrev.handleClick(x, y, button);
}
if (pageNext.contains(x, y)) {
pageNext.handleClick(x, y, button);
}
}
public void restartFilter() {
updateFilter.restart();
}
protected void updateItemList(List<ItemStack> newItems) {
this.newItems = new ArrayList<>(newItems);
}
@Override
public void refresh(GuiContainer gui) {
if (this.newItems != null) {
this.realItems = this.newItems;
this.newItems = null;
onItemsChanged();
}
super.refresh(gui);
}
@Override
protected void beforeDrawSlot(@Nullable ItemPanelSlot focused, int slotIdx, Rectangle4i rect) {
if (isSelected(getItem(slotIdx))) {
GuiDraw.drawRect(rect.x, rect.y, rect.w, rect.h, 0xee555555);
} else {
super.beforeDrawSlot(focused, slotIdx, rect);
}
}
protected abstract boolean isSelected(ItemStack stack);
protected abstract ItemFilter getFilter();
}
@@ -0,0 +1,396 @@
package codechicken.nei.config.preset;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import net.minecraft.client.renderer.RenderHelper;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumChatFormatting;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import codechicken.core.gui.GuiWidget;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemList;
import codechicken.nei.ItemList.AllMultiItemFilter;
import codechicken.nei.ItemList.AnyMultiItemFilter;
import codechicken.nei.ItemList.NegatedItemFilter;
import codechicken.nei.ItemPanel.ItemPanelSlot;
import codechicken.nei.ItemsGrid;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.PresetsList;
import codechicken.nei.PresetsList.Preset;
import codechicken.nei.SearchField.GuiSearchField;
import codechicken.nei.TextField;
import codechicken.nei.api.ItemFilter;
import codechicken.nei.api.ItemInfo;
import codechicken.nei.guihook.GuiContainerManager;
import codechicken.nei.guihook.IContainerTooltipHandler;
import codechicken.nei.util.TextHistory;
import cpw.mods.fml.common.registry.GameRegistry;
public class RightPanel extends GuiWidget {
protected static class MouseSelection {
public int startX = -1;
public int startY = -1;
public int startIndex = -1;
public int endIndex = -1;
public Set<ItemStack> items = new HashSet<>();
public boolean append = true;
public MouseSelection(int slotIndex, Rectangle4i rec, boolean ppnd) {
append = ppnd;
endIndex = slotIndex;
startIndex = slotIndex;
startX = rec.x;
startY = rec.y;
}
}
protected static abstract class PresetSearchField extends TextField {
private static final TextHistory history = new TextHistory();
public PresetSearchField(String ident) {
super(ident);
}
@Override
protected void initInternalTextField() {
field = new GuiSearchField();
field.setMaxStringLength(maxSearchLength);
field.setCursorPositionZero();
}
@Override
public int getTextColour() {
if (!text().isEmpty()) {
return focused() ? 0xFFcc3300 : 0xFF993300;
} else {
return focused() ? 0xFFE0E0E0 : 0xFF909090;
}
}
@Override
public void lastKeyTyped(int keyID, char keyChar) {
if (!focused() && NEIClientConfig.isKeyHashDown("gui.search")) {
setFocus(true);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getprevioussearch")) {
handleNavigateHistory(TextHistory.Direction.PREVIOUS);
}
if (focused() && NEIClientConfig.isKeyHashDown("gui.getnextsearch")) {
handleNavigateHistory(TextHistory.Direction.NEXT);
}
}
@Override
public String filterText(String s) {
return EnumChatFormatting.getTextWithoutFormattingCodes(s);
}
public ItemFilter getFilter() {
return ((GuiSearchField) field).getFilter();
}
@Override
public void setFocus(boolean focus) {
final boolean previousFocus = field.isFocused();
if (previousFocus != focus) {
history.add(text());
}
super.setFocus(focus);
}
private boolean handleNavigateHistory(TextHistory.Direction direction) {
if (focused()) {
return history.get(direction, text()).map(newText -> {
setText(newText);
return true;
}).orElse(false);
}
return false;
}
}
protected static final int INPUT_HEIGHT = 20;
protected static final int BUTTON_SIZE = 16;
protected final PresetItemsGrid grid = new PresetItemsGrid() {
@Override
protected ItemFilter getFilter() {
AllMultiItemFilter filter = new AllMultiItemFilter();
filter.filters.add(item -> !ItemInfo.hiddenItems.contains(item));
filter.filters.add(searchField.getFilter());
if (enabledPresets.isChecked()) {
AllMultiItemFilter andFilter = new AllMultiItemFilter();
AnyMultiItemFilter orFilter = new AnyMultiItemFilter();
Set<String> identifiers = PresetsList.presets.stream().flatMap(p -> p.items.stream())
.collect(Collectors.toSet());
andFilter.filters.add(item -> !identifiers.contains(Preset.getIdentifier(item)));
andFilter.filters.add(new NegatedItemFilter(ItemList.collapsibleItems.getItemFilter()));
if (slotIndex != -1) {
orFilter.filters.add(PresetsList.presets.get(slotIndex));
}
orFilter.filters.add(andFilter);
filter.filters.add(orFilter);
}
return filter;
}
@Override
protected boolean isSelected(ItemStack stack) {
if (mouseSelection != null && mouseSelection.items.contains(stack)) {
return mouseSelection.append != false;
}
return preset.items.contains(Preset.getIdentifier(stack));
}
};
protected CheckboxButton enabledPresets;
protected final Preset preset;
protected final int slotIndex;
protected MouseSelection mouseSelection;
protected final PresetSearchField searchField = new PresetSearchField("preset-search") {
@Override
public void onTextChange(String oldText) {
final String newText = text();
if (!newText.equals(oldText)) {
grid.restartFilter();
}
}
};
public RightPanel(Preset preset, int slotIndex) {
super(1, 0, 2, 2);
this.slotIndex = slotIndex;
this.preset = preset;
enabledPresets = new CheckboxButton(NEIClientUtils.translate("presets.filter")) {
@Override
protected void onChange() {
grid.restartFilter();
}
};
enabledPresets.setChecked(true);
grid.restartFilter();
}
public void mouseClicked(int x, int y, int button) {
grid.mouseClicked(x, y, button);
if (enabledPresets.contains(x, y)) {
enabledPresets.handleClick(x, y, button);
}
if (searchField.contains(x, y)) {
searchField.handleClick(x, y, button);
} else {
searchField.onGuiClick(x, y);
}
if (mouseSelection == null && (button == 0 || button == 1)) {
ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null) {
mouseSelection = new MouseSelection(slot.slotIndex, grid.getItemRect(slot.slotIndex), button == 0);
}
}
}
protected void onItemsChanges() {}
public void mouseMovedOrUp(int x, int y, int button) {
searchField.mouseUp(x, y, button);
if (mouseSelection != null && (button == 0 || button == 1)) {
ItemPanelSlot hoverSlot = grid.getSlotMouseOver(x, y);
if (hoverSlot != null && hoverSlot.slotIndex == mouseSelection.startIndex) {
setHidden(hoverSlot.item, button == 0);
} else if (!mouseSelection.items.isEmpty()) {
for (ItemStack stack : mouseSelection.items) {
hideItem(stack, mouseSelection.append);
}
}
mouseSelection = null;
onItemsChanges();
}
}
protected void setHidden(final ItemStack stack, final boolean append) {
if (NEIClientUtils.shiftKey()) {
final List<ItemStack> items = grid.getItems();
for (int i = 0; i < items.size(); i++) {
if (stack.getItem().equals(items.get(i).getItem())) {
hideItem(items.get(i), append);
}
}
} else if (NEIClientUtils.controlKey()) {
final String modId = getModId(stack);
if (modId == null) {
hideItem(stack, append);
} else {
final List<ItemStack> items = grid.getItems();
for (int i = 0; i < items.size(); i++) {
final String mod = getModId(items.get(i));
if (mod != null && mod.equals(modId)) {
hideItem(items.get(i), append);
}
}
}
} else {
hideItem(stack, append);
}
}
protected void hideItem(final ItemStack stack, boolean append) {
if (append) {
preset.items.add(Preset.getIdentifier(stack));
} else {
preset.items.remove(Preset.getIdentifier(stack));
}
}
protected static String getModId(final ItemStack stack) {
try {
return GameRegistry.findUniqueIdentifierFor(stack.getItem()).modId;
} catch (Exception ignored) {}
return null;
}
public void mouseDragged(int x, int y, int button, long time) {
searchField.mouseDragged(x, y, button, time);
if (mouseSelection != null && (button == 0 || button == 1)) {
final ItemPanelSlot slot = grid.getSlotMouseOver(x, y);
if (slot != null && slot.slotIndex != mouseSelection.endIndex) {
mouseSelection.endIndex = slot.slotIndex;
mouseSelection.items.clear();
final Rectangle4i rec = grid.getItemRect(slot.slotIndex);
final Rectangle4i sel = new Rectangle4i(
Math.min(rec.x, mouseSelection.startX),
Math.min(rec.y, mouseSelection.startY),
Math.max(rec.x, mouseSelection.startX) - Math.min(rec.x, mouseSelection.startX),
Math.max(rec.y, mouseSelection.startY) - Math.min(rec.y, mouseSelection.startY));
for (int ix = sel.x; ix <= sel.x + sel.w; ix += ItemsGrid.SLOT_SIZE) {
for (int iy = sel.y; iy <= sel.y + sel.h; iy += ItemsGrid.SLOT_SIZE) {
ItemPanelSlot over = grid.getSlotMouseOver(ix, iy);
if (over != null) {
mouseSelection.items.add(over.item);
}
}
}
}
}
}
public void update() {
enabledPresets.w = 20;
enabledPresets.h = INPUT_HEIGHT;
enabledPresets.x = this.x;
enabledPresets.y = this.y + this.height - 2 - INPUT_HEIGHT;
searchField.w = this.width - enabledPresets.w - 3;
searchField.h = INPUT_HEIGHT;
searchField.x = enabledPresets.x + enabledPresets.w + 3;
searchField.y = enabledPresets.y;
grid.setGridSize(this.x, this.y, this.width, searchField.y - this.y);
grid.refresh(null);
}
public void draw(int mousex, int mousey, float frame) {
enabledPresets.draw(mousex, mousey);
searchField.draw(mousex, mousey);
RenderHelper.enableGUIStandardItemLighting();
GL11.glPushMatrix();
GL11.glEnable(GL12.GL_RESCALE_NORMAL);
grid.draw(mousex, mousey);
GL11.glDisable(GL12.GL_RESCALE_NORMAL);
GL11.glPopMatrix();
RenderHelper.enableStandardItemLighting();
}
public List<String> handleTooltip(int mousex, int mousey, List<String> tooltip) {
ItemPanelSlot over = grid.getSlotMouseOver(mousex, mousey);
if (over != null) {
tooltip = GuiContainerManager.itemDisplayNameMultiline(over.item, null, true);
synchronized (GuiContainerManager.tooltipHandlers) {
for (IContainerTooltipHandler handler : GuiContainerManager.tooltipHandlers) {
tooltip = handler.handleItemTooltip(null, over.item, mousex, mousey, tooltip);
}
}
if (tooltip.size() > 0) {
tooltip.set(0, tooltip.get(0) + GuiDraw.TOOLTIP_LINESPACE); // add space after 'title'
}
} else if (enabledPresets.contains(mousex, mousey)) {
tooltip.add(NEIClientUtils.translate("presets.filter.tip"));
}
return tooltip;
}
public void keyTyped(char c, int keycode) {
searchField.handleKeyPress(keycode, c);
}
public void mouseScrolled(int x, int y, int scroll) {
if (grid.contains(x, y)) {
grid.shiftPage(-scroll);
}
}
}
@@ -11,7 +11,6 @@ import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.WeakHashMap;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTBase;
@@ -23,6 +22,7 @@ import net.minecraftforge.fluids.IFluidContainerItem;
import org.apache.commons.io.IOUtils;
import codechicken.nei.ItemStackMap;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.api.IStackStringifyHandler;
import codechicken.nei.recipe.stackinfo.DefaultStackStringifyHandler;
@@ -32,7 +32,7 @@ public class StackInfo {
public static final ArrayList<IStackStringifyHandler> stackStringifyHandlers = new ArrayList<>();
private static final HashMap<String, HashMap<String, String[]>> guidfilters = new HashMap<>();
private static final WeakHashMap<ItemStack, String> guidcache = new WeakHashMap<>();
private static final ItemStackMap<String> guidcache = new ItemStackMap<>();
private static final LinkedHashMap<ItemStack, FluidStack> fluidcache = new LinkedHashMap<ItemStack, FluidStack>() {
@Override
@@ -119,64 +119,67 @@ public class StackInfo {
}
public static String getItemStackGUID(ItemStack stack) {
if (!guidcache.containsKey(stack)) {
String guid = guidcache.get(stack);
final NBTTagCompound nbTag = itemStackToNBT(stack, false);
if (guid != null) {
return guid;
}
if (nbTag == null) {
return null;
}
final NBTTagCompound nbTag = itemStackToNBT(stack, false);
nbTag.removeTag("Count");
if (nbTag == null) {
return null;
}
if (nbTag.getShort("Damage") == 0) {
nbTag.removeTag("Damage");
}
nbTag.removeTag("Count");
if (nbTag.hasKey("tag") && nbTag.getCompoundTag("tag").hasNoTags()) {
nbTag.removeTag("tag");
}
if (nbTag.getShort("Damage") == 0) {
nbTag.removeTag("Damage");
}
if (nbTag.hasKey("strId") && guidfilters.containsKey(nbTag.getString("strId"))) {
final ArrayList<String> keys = new ArrayList<>();
final String strId = nbTag.getString("strId");
if (nbTag.hasKey("tag") && nbTag.getCompoundTag("tag").hasNoTags()) {
nbTag.removeTag("tag");
}
keys.add(strId);
if (nbTag.hasKey("strId") && guidfilters.containsKey(nbTag.getString("strId"))) {
final ArrayList<String> keys = new ArrayList<>();
final String strId = nbTag.getString("strId");
guidfilters.get(strId).forEach((key, rule) -> {
Object local = nbTag;
keys.add(strId);
for (int i = 0; i < rule.length; i++) {
guidfilters.get(strId).forEach((key, rule) -> {
Object local = nbTag;
try {
for (int i = 0; i < rule.length; i++) {
if (local instanceof NBTTagCompound) {
local = ((NBTTagCompound) local).getTag(rule[i]);
} else if (local instanceof NBTTagList) {
local = ((NBTTagList) local).tagList.get(Integer.parseInt(rule[i]));
} else {
break;
}
try {
} catch (Throwable e) {
if (local instanceof NBTTagCompound) {
local = ((NBTTagCompound) local).getTag(rule[i]);
} else if (local instanceof NBTTagList) {
local = ((NBTTagList) local).tagList.get(Integer.parseInt(rule[i]));
} else {
break;
}
}
if (local instanceof NBTBase) {
keys.add(((NBTBase) local).toString());
} else if (local != null) {
keys.add(String.valueOf(local));
} catch (Throwable e) {
break;
}
});
}
synchronized (guidcache) {
guidcache.put(stack, keys.toString());
}
} else {
synchronized (guidcache) {
guidcache.put(stack, nbTag.toString());
if (local instanceof NBTBase) {
keys.add(((NBTBase) local).toString());
} else if (local != null) {
keys.add(String.valueOf(local));
}
});
synchronized (guidcache) {
guidcache.put(stack, keys.toString());
}
} else {
synchronized (guidcache) {
guidcache.put(stack, nbTag.toString());
}
}
@@ -35,11 +35,11 @@ import com.google.common.base.Stopwatch;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.ItemList;
import codechicken.nei.ItemList.AllMultiItemFilter;
import codechicken.nei.LayoutManager;
import codechicken.nei.NEIClientConfig;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.NEIServerUtils;
import codechicken.nei.PositionedStack;
import codechicken.nei.PresetsList;
import codechicken.nei.api.DefaultOverlayRenderer;
import codechicken.nei.api.IOverlayHandler;
import codechicken.nei.api.IRecipeOverlayRenderer;
@@ -433,7 +433,7 @@ public abstract class TemplateRecipeHandler implements ICraftingHandler, IUsageH
protected static ItemFilter getItemFilter() {
return new AllMultiItemFilter(
item -> !ItemInfo.hiddenItems.contains(item),
LayoutManager.presetsPanel != null ? LayoutManager.presetsPanel.getFilter() : null,
PresetsList.getItemFilter(),
GuiRecipe.searchField != null ? GuiRecipe.searchField.getFilter() : null);
}
@@ -0,0 +1,20 @@
# Collapsible Items Filters
#
# One line - one group
# Item added in first valid group
# | - logical or. multi-item search (wrench|hammer)
# $ - search by ore dictionary ($ore)
# ! - logical not. exclude items that match the following expression (-@minecraft)
# r/.../ - standard java regex (@r/m\w{6}ft/ = @minecraft)
# 0 - damage filter
# 0-12 - damage range filter
# , - logical or in token
#
#
minecraft:spawn_egg
minecraft:mob_spawner
minecraft:record_
#splash
minecraft:potion >16000
#lingering
minecraft:potion >8000 <9000
+30 -10
View File
@@ -13,6 +13,9 @@ nei.bookmark.pullBookmarkedItems.tip=Pull all bookmarked items from storage to i
nei.itempanel.quantity.default=One stack
nei.itempanel.loading=Loading Item List...
nei.itempanel.collapsed.button.tip=Toggle Groups
nei.itempanel.collapsed.hint.expand=Alt-Click to expand (%d items)
nei.itempanel.collapsed.hint.collapse=Alt-Click to collapse (%d items)
nei.enchant=Enchant
nei.enchant.level=Level
@@ -85,6 +88,7 @@ nei.chat.chunkoverlay.3=Chunk Overlay: GT Ore Veins
nei.options=NEI Options
nei.options.back=Back
nei.options.save=Save
nei.options.world=World
nei.options.global=Global
nei.options.global.tip.0=Options apply to all worlds
@@ -266,6 +270,14 @@ nei.options.inventory.invertMouseScrollTransfer.false=False
nei.options.inventory.cacheItemRendering=Cache Item Rendering
nei.options.inventory.cacheItemRendering.true=True
nei.options.inventory.cacheItemRendering.false=False
nei.options.inventory.collapsibleItems=Collapsible Items
nei.options.inventory.collapsibleItems.enabled=Collapsible Items
nei.options.inventory.collapsibleItems.enabled.true=Enabled
nei.options.inventory.collapsibleItems.enabled.false=Disabled
nei.options.inventory.collapsibleItems.expandedColor=Expanded Color
nei.options.inventory.collapsibleItems.collapsedColor=Collapsed Color
nei.options.inventory.collapsibleItems.reloadLabel=Reload
nei.options.inventory.collapsibleItems.reloadButton=Run
nei.options.inventory.history=History Panel
nei.options.inventory.history.enabled=History Panel Visibility
nei.options.inventory.history.enabled.true=Enabled
@@ -294,6 +306,7 @@ nei.options.world.highlight_tips.show=Shown
nei.options.world.highlight_tips.sample=Sample
nei.options.world.panels=Panels Settings
nei.options.world.presets=Presets List
nei.options.tools=Tools
nei.options.tools.handler_load_from_config=Load handlers from Config
@@ -391,13 +404,20 @@ nei.subsets.Items.Weapons.Ranged=Ranged
nei.subsets.Items.Weapons.Swords=Swords
nei.subsets.Mod=Mod
nei.presets.blacklist.label=B
nei.presets.blacklist.tooltip=Blacklist
nei.presets.whitelist.label=W
nei.presets.whitelist.tooltip=Whitelist
nei.presets.blacklistPlus.label=B+
nei.presets.blacklistPlus.tooltip=Blacklist Plus
nei.presets.textfield.tooltip.1=Enter - save
nei.presets.textfield.tooltip.2=Escape - cancel
nei.presets.label.tooltip=Double click to edit
nei.presets.label.selected=%s Presets
nei.presets.new=New Preset
nei.presets.create=Create Preset
nei.presets.update=Update Preset
nei.presets.enabled=Enabled
nei.presets.filter=F
nei.presets.filter.tip=Hide items from another active presets
nei.presets.name=Preset Name
nei.presets.mode=Mode
nei.presets.mode.hide=Hide
nei.presets.mode.hide.char=H
nei.presets.mode.hide.tip=Hide items in panel
nei.presets.mode.remove=Remove
nei.presets.mode.remove.tip=Hide items in panel and it recipes
nei.presets.mode.remove.char=R
nei.presets.mode.group=Group
nei.presets.mode.group.tip=Create custom collapsible items group
nei.presets.mode.group.char=G
@@ -316,12 +316,3 @@ nei.subsets.Items.Weapons=武器
nei.subsets.Items.Weapons.Ranged=远程
nei.subsets.Items.Weapons.Swords=剑
nei.subsets.Mod=Mod
nei.presets.blacklist.label=黑
nei.presets.blacklist.tooltip=黑名单
nei.presets.whitelist.label=白
nei.presets.whitelist.tooltip=白名单
nei.presets.textfield.tooltip.1=Enter - 保存
nei.presets.textfield.tooltip.2=Esc - 取消
nei.presets.label.tooltip=双击编辑
nei.presets.label.selected=%s 预设