From 66abc317e5fc36a397ca1cc919e388fbe143956b Mon Sep 17 00:00:00 2001 From: shedaniel Date: Wed, 1 Apr 2020 20:01:34 +0800 Subject: ScrollingContainer & SubsetsMenu && 20w18b Signed-off-by: shedaniel --- .../me/shedaniel/rei/gui/subsets/SubsetsMenu.java | 256 +++++++++++++++++++++ 1 file changed, 256 insertions(+) create mode 100644 src/main/java/me/shedaniel/rei/gui/subsets/SubsetsMenu.java (limited to 'src/main/java/me/shedaniel/rei/gui/subsets/SubsetsMenu.java') diff --git a/src/main/java/me/shedaniel/rei/gui/subsets/SubsetsMenu.java b/src/main/java/me/shedaniel/rei/gui/subsets/SubsetsMenu.java new file mode 100644 index 000000000..676942350 --- /dev/null +++ b/src/main/java/me/shedaniel/rei/gui/subsets/SubsetsMenu.java @@ -0,0 +1,256 @@ +package me.shedaniel.rei.gui.subsets; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; +import me.shedaniel.clothconfig2.ClothConfigInitializer; +import me.shedaniel.clothconfig2.api.ScissorsHandler; +import me.shedaniel.math.Point; +import me.shedaniel.math.Rectangle; +import me.shedaniel.rei.RoughlyEnoughItemsCore; +import me.shedaniel.rei.api.EntryRegistry; +import me.shedaniel.rei.api.EntryStack; +import me.shedaniel.rei.api.subsets.SubsetsRegistry; +import me.shedaniel.rei.gui.subsets.entries.EntryStackMenuEntry; +import me.shedaniel.rei.gui.subsets.entries.SubMenuEntry; +import me.shedaniel.rei.gui.widget.LateRenderable; +import me.shedaniel.rei.gui.widget.ScrollingContainer; +import me.shedaniel.rei.gui.widget.WidgetWithBounds; +import me.shedaniel.rei.impl.EntryRegistryImpl; +import me.shedaniel.rei.utils.CollectionUtils; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.item.Item; +import net.minecraft.item.ItemGroup; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.util.registry.Registry; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +@ApiStatus.Experimental +@ApiStatus.Internal +public class SubsetsMenu extends WidgetWithBounds implements LateRenderable { + public final Point menuStartPoint; + private final List entries = Lists.newArrayList(); + public final ScrollingContainer scrolling = new ScrollingContainer() { + @Override + public int getMaxScrollHeight() { + int i = 0; + for (SubsetsMenuEntry entry : children()) { + i += entry.getEntryHeight(); + } + return i; + } + + @Override + public Rectangle getBounds() { + return SubsetsMenu.this.getInnerBounds(); + } + + @Override + public boolean hasScrollBar() { + return SubsetsMenu.this.hasScrollBar(); + } + }; + + public SubsetsMenu(Point menuStartPoint, Collection entries) { + this.menuStartPoint = menuStartPoint; + buildEntries(entries); + } + + public static SubsetsMenu createFromRegistry(Point menuStartPoint) { + List stacks = EntryRegistry.getInstance().getStacksList(); + Map entries = Maps.newHashMap(); + { + // All Entries group + Map allEntries = getOrCreateSubEntryInMap(entries, "roughlyenoughitems:all_entries"); + for (EntryStack stack : stacks) { + putEntryInMap(allEntries, stack); + } + } + { + // Item Groups group + Map itemGroups = getOrCreateSubEntryInMap(entries, "roughlyenoughitems:item_groups"); + for (Item item : Registry.ITEM) { + ItemGroup group = item.getGroup(); + if (group == null) + continue; + DefaultedList list; + try { + list = new EntryRegistryImpl.DefaultedLinkedList<>(Lists.newLinkedList(), null); + item.appendStacks(group, list); + if (list.isEmpty()) + list.add(item.getStackForRender()); + Map groupMenu = getOrCreateSubEntryInMap(itemGroups, "_item_group_" + group.getId()); + for (ItemStack stack : list) { + putEntryInMap(groupMenu, EntryStack.create(stack)); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } + Set paths = SubsetsRegistry.INSTANCE.getPaths(); + for (String path : paths) { + Map lastMap = entries; + String[] pathSegments = path.split("/"); + for (String pathSegment : pathSegments) { + lastMap = getOrCreateSubEntryInMap(lastMap, pathSegment); + } + for (EntryStack entry : SubsetsRegistry.INSTANCE.getPathEntries(path)) { + EntryStack firstStack = CollectionUtils.findFirstOrNullEqualsEntryIgnoreAmount(stacks, entry); + if (firstStack != null) + putEntryInMap(lastMap, firstStack); + } + } + return new SubsetsMenu(menuStartPoint, buildEntries(entries)); + } + + private static Map getOrCreateSubEntryInMap(Map parent, String pathSegment) { + putEntryInMap(parent, pathSegment); + return (Map) parent.get(pathSegment); + } + + private static void putEntryInMap(Map parent, String pathSegment) { + if (!parent.containsKey(pathSegment)) { + parent.put(pathSegment, Maps.newHashMap()); + } + } + + private static void putEntryInMap(Map parent, EntryStack stack) { + Set items = (Set) parent.get("items"); + if (items == null) { + items = Sets.newLinkedHashSet(); + parent.put("items", items); + } + items.add(stack); + } + + private static List buildEntries(Map map) { + List entries = Lists.newArrayList(); + for (Map.Entry entry : map.entrySet()) { + if (entry.getKey().equals("items")) { + Set items = (Set) entry.getValue(); + for (EntryStack item : items) { + entries.add(new EntryStackMenuEntry(item)); + } + } else { + Map entryMap = (Map) entry.getValue(); + if (entry.getKey().startsWith("_item_group_")) { + entries.add(new SubMenuEntry(I18n.translate(entry.getKey().replace("_item_group_", "itemGroup.")), buildEntries(entryMap))); + } else { + String translationKey = "subsets.rei." + entry.getKey().replace(':', '.'); + if (!I18n.hasTranslation(translationKey)) + RoughlyEnoughItemsCore.LOGGER.warn("[REI] Subsets menu " + translationKey + " does not have a translation"); + entries.add(new SubMenuEntry(I18n.translate(translationKey), buildEntries(entryMap))); + } + } + } + return entries; + } + + @SuppressWarnings("deprecation") + private void buildEntries(Collection entries) { + this.entries.clear(); + this.entries.addAll(entries); + this.entries.sort(Comparator.comparing(entry -> entry instanceof SubMenuEntry ? 0 : 1).thenComparing(entry -> entry instanceof SubMenuEntry ? ((SubMenuEntry) entry).text : "")); + for (SubsetsMenuEntry entry : this.entries) { + entry.parent = this; + } + } + + @Override + public @NotNull Rectangle getBounds() { + return new Rectangle(menuStartPoint.x, menuStartPoint.y, getMaxEntryWidth() + 2 + (hasScrollBar() ? 6 : 0), getInnerHeight() + 2); + } + + public Rectangle getInnerBounds() { + return new Rectangle(menuStartPoint.x + 1, menuStartPoint.y + 1, getMaxEntryWidth() + (hasScrollBar() ? 6 : 0), getInnerHeight()); + } + + public boolean hasScrollBar() { + return scrolling.getMaxScrollHeight() > getInnerHeight(); + } + + public int getInnerHeight() { + return Math.min(scrolling.getMaxScrollHeight(), minecraft.currentScreen.height - 20 - menuStartPoint.y); + } + + public int getMaxEntryWidth() { + int i = 0; + for (SubsetsMenuEntry entry : children()) { + if (entry.getEntryWidth() > i) + i = entry.getEntryWidth(); + } + return Math.max(10, i); + } + + @Override + public void render(int mouseX, int mouseY, float delta) { + Rectangle bounds = getBounds(); + Rectangle innerBounds = getInnerBounds(); + fill(bounds.x, bounds.y, bounds.getMaxX(), bounds.getMaxY(), -6250336); + fill(innerBounds.x, innerBounds.y, innerBounds.getMaxX(), innerBounds.getMaxY(), -16777216); + boolean contains = innerBounds.contains(mouseX, mouseY); + SubsetsMenuEntry focused = getFocused() instanceof SubsetsMenuEntry ? (SubsetsMenuEntry) getFocused() : null; + int currentY = (int) (innerBounds.y - scrolling.scrollAmount); + for (SubsetsMenuEntry child : children()) { + boolean containsMouse = contains && mouseY >= currentY && mouseY < currentY + child.getEntryHeight(); + if (containsMouse) { + focused = child; + } + currentY += child.getEntryHeight(); + } + currentY = (int) (innerBounds.y - scrolling.scrollAmount); + ScissorsHandler.INSTANCE.scissor(scrolling.getScissorBounds()); + for (SubsetsMenuEntry child : children()) { + boolean rendering = currentY + child.getEntryHeight() >= innerBounds.y && currentY <= innerBounds.getMaxY(); + boolean containsMouse = contains && mouseY >= currentY && mouseY < currentY + child.getEntryHeight(); + child.updateInformation(innerBounds.x, currentY, focused == child || containsMouse, containsMouse, rendering, getMaxEntryWidth()); + if (rendering) + child.render(mouseX, mouseY, delta); + currentY += child.getEntryHeight(); + } + ScissorsHandler.INSTANCE.removeLastScissor(); + setFocused(focused); + scrolling.renderScrollBar(); + scrolling.updatePosition(delta); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + if (scrolling.updateDraggingState(mouseX, mouseY, button)) + return true; + return super.mouseClicked(mouseX, mouseY, button); + } + + @Override + public boolean mouseDragged(double mouseX, double mouseY, int button, double deltaX, double deltaY) { + if (scrolling.mouseDragged(mouseX, mouseY, button, deltaX, deltaY)) + return true; + return super.mouseDragged(mouseX, mouseY, button, deltaX, deltaY); + } + + @Override + public boolean mouseScrolled(double mouseX, double mouseY, double amount) { + if (getInnerBounds().contains(mouseX, mouseY)) { + scrolling.offset(ClothConfigInitializer.getScrollStep() * -amount, true); + return true; + } + for (SubsetsMenuEntry child : children()) { + if (child instanceof SubMenuEntry) { + if (child.mouseScrolled(mouseX, mouseY, amount)) + return true; + } + } + return super.mouseScrolled(mouseX, mouseY, amount); + } + + @Override + public List children() { + return entries; + } +} -- cgit