shedaniel 5 years ago
parent
commit
b3ed9e1af0
42 changed files with 606 additions and 307 deletions
  1. 1 1
      gradle.properties
  2. 25 0
      src/main/java/me/shedaniel/rei/api/OptimalEntryStack.java
  3. 0 1
      src/main/java/me/shedaniel/rei/api/RecipeCategory.java
  4. 1 6
      src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java
  5. 29 12
      src/main/java/me/shedaniel/rei/gui/OverlaySearchField.java
  6. 5 2
      src/main/java/me/shedaniel/rei/gui/PreRecipeViewingScreen.java
  7. 4 1
      src/main/java/me/shedaniel/rei/gui/RecipeViewingScreen.java
  8. 3 0
      src/main/java/me/shedaniel/rei/gui/VillagerRecipeViewingScreen.java
  9. 16 16
      src/main/java/me/shedaniel/rei/gui/credits/CreditsEntryListWidget.java
  10. 8 8
      src/main/java/me/shedaniel/rei/gui/toast/CopyRecipeIdentifierToast.java
  11. 3 0
      src/main/java/me/shedaniel/rei/gui/widget/AutoCraftingButtonWidget.java
  12. 3 0
      src/main/java/me/shedaniel/rei/gui/widget/ButtonWidget.java
  13. 27 0
      src/main/java/me/shedaniel/rei/gui/widget/ClickableActionedLabelWidget.java
  14. 8 8
      src/main/java/me/shedaniel/rei/gui/widget/ClickableLabelWidget.java
  15. 3 0
      src/main/java/me/shedaniel/rei/gui/widget/CraftableToggleButtonWidget.java
  16. 3 0
      src/main/java/me/shedaniel/rei/gui/widget/DraggableWidget.java
  17. 100 17
      src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java
  18. 26 9
      src/main/java/me/shedaniel/rei/gui/widget/EntryWidget.java
  19. 4 1
      src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java
  20. 27 0
      src/main/java/me/shedaniel/rei/gui/widget/LabelWidget.java
  21. 6 0
      src/main/java/me/shedaniel/rei/gui/widget/RecipeArrowWidget.java
  22. 6 4
      src/main/java/me/shedaniel/rei/gui/widget/RecipeChoosePageWidget.java
  23. 5 3
      src/main/java/me/shedaniel/rei/gui/widget/TabWidget.java
  24. 94 84
      src/main/java/me/shedaniel/rei/gui/widget/TextFieldWidget.java
  25. 18 0
      src/main/java/me/shedaniel/rei/gui/widget/Widget.java
  26. 1 15
      src/main/java/me/shedaniel/rei/gui/widget/WidgetWithBounds.java
  27. 51 10
      src/main/java/me/shedaniel/rei/impl/ConfigManagerImpl.java
  28. 2 2
      src/main/java/me/shedaniel/rei/impl/ConfigObjectImpl.java
  29. 59 41
      src/main/java/me/shedaniel/rei/impl/ItemEntryStack.java
  30. 2 1
      src/main/java/me/shedaniel/rei/impl/ScreenHelper.java
  31. 10 11
      src/main/java/me/shedaniel/rei/impl/Weather.java
  32. 6 6
      src/main/java/me/shedaniel/rei/listeners/ContainerScreenHooks.java
  33. 6 6
      src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java
  34. 1 1
      src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultRecipeBookHandler.java
  35. 3 3
      src/main/java/me/shedaniel/rei/plugin/brewing/BrewingRecipe.java
  36. 5 5
      src/main/java/me/shedaniel/rei/plugin/campfire/DefaultCampfireCategory.java
  37. 10 10
      src/main/java/me/shedaniel/rei/plugin/composting/DefaultCompostingDisplay.java
  38. 8 8
      src/main/java/me/shedaniel/rei/plugin/cooking/DefaultCookingCategory.java
  39. 1 1
      src/main/java/me/shedaniel/rei/plugin/information/DefaultInformationCategory.java
  40. 8 8
      src/main/java/me/shedaniel/rei/plugin/stonecutting/DefaultStoneCuttingDisplay.java
  41. 6 6
      src/main/java/me/shedaniel/rei/plugin/stripping/DefaultStrippingCategory.java
  42. 2 0
      src/main/resources/assets/roughlyenoughitems/lang/en_us.json

+ 1 - 1
gradle.properties

@@ -1,4 +1,4 @@
-mod_version=3.3.10
+mod_version=3.3.11
 minecraft_version=1.15.1
 minecraft_version=1.15.1
 yarn_version=1.15.1+build.1
 yarn_version=1.15.1+build.1
 fabricloader_version=0.7.2+build.174
 fabricloader_version=0.7.2+build.174

+ 25 - 0
src/main/java/me/shedaniel/rei/api/OptimalEntryStack.java

@@ -0,0 +1,25 @@
+/*
+ * Roughly Enough Items by Danielshe.
+ * Licensed under the MIT License.
+ */
+
+package me.shedaniel.rei.api;
+
+import me.shedaniel.math.api.Rectangle;
+import me.shedaniel.rei.api.annotations.Internal;
+
+@Internal
+@Deprecated
+public interface OptimalEntryStack {
+    default void optimisedRenderStart(float delta) {
+    }
+    
+    default void optimisedRenderBase(Rectangle bounds, int mouseX, int mouseY, float delta) {
+    }
+    
+    default void optimisedRenderOverlay(Rectangle bounds, int mouseX, int mouseY, float delta) {
+    }
+    
+    default void optimisedRenderEnd(float delta) {
+    }
+}

+ 0 - 1
src/main/java/me/shedaniel/rei/api/RecipeCategory.java

@@ -9,7 +9,6 @@ import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.rei.gui.RecipeViewingScreen;
 import me.shedaniel.rei.gui.RecipeViewingScreen;
 import me.shedaniel.rei.gui.entries.RecipeEntry;
 import me.shedaniel.rei.gui.entries.RecipeEntry;
 import me.shedaniel.rei.gui.entries.SimpleRecipeEntry;
 import me.shedaniel.rei.gui.entries.SimpleRecipeEntry;
-import me.shedaniel.rei.gui.widget.CategoryBaseWidget;
 import me.shedaniel.rei.gui.widget.PanelWidget;
 import me.shedaniel.rei.gui.widget.PanelWidget;
 import me.shedaniel.rei.gui.widget.RecipeBaseWidget;
 import me.shedaniel.rei.gui.widget.RecipeBaseWidget;
 import me.shedaniel.rei.gui.widget.Widget;
 import me.shedaniel.rei.gui.widget.Widget;

+ 1 - 6
src/main/java/me/shedaniel/rei/gui/ContainerScreenOverlay.java

@@ -293,11 +293,6 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
                     super.render(mouseX, mouseY, delta);
                     super.render(mouseX, mouseY, delta);
                 }
                 }
                 
                 
-                @Override
-                public Optional<String> getTooltips() {
-                    return Optional.ofNullable(I18n.translate("text.rei.go_back_first_page"));
-                }
-                
                 @Override
                 @Override
                 public void onLabelClicked() {
                 public void onLabelClicked() {
                     MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F));
                     MinecraftClient.getInstance().getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F));
@@ -309,7 +304,7 @@ public class ContainerScreenOverlay extends WidgetWithBounds {
                 public boolean changeFocus(boolean boolean_1) {
                 public boolean changeFocus(boolean boolean_1) {
                     return false;
                     return false;
                 }
                 }
-            });
+            }.tooltip(() -> I18n.translate("text.rei.go_back_first_page")));
         }
         }
         if (ConfigObject.getInstance().isCraftableFilterEnabled())
         if (ConfigObject.getInstance().isCraftableFilterEnabled())
             this.widgets.add(toggleButtonWidget = new CraftableToggleButtonWidget(getCraftableToggleArea()) {
             this.widgets.add(toggleButtonWidget = new CraftableToggleButtonWidget(getCraftableToggleArea()) {

+ 29 - 12
src/main/java/me/shedaniel/rei/gui/OverlaySearchField.java

@@ -7,6 +7,7 @@ package me.shedaniel.rei.gui;
 
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;
 import com.mojang.blaze3d.systems.RenderSystem;
 import com.mojang.blaze3d.systems.RenderSystem;
+import me.shedaniel.math.api.Point;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.gui.widget.TextFieldWidget;
 import me.shedaniel.rei.gui.widget.TextFieldWidget;
@@ -16,15 +17,18 @@ import net.minecraft.client.resource.language.I18n;
 import net.minecraft.client.sound.PositionedSoundInstance;
 import net.minecraft.client.sound.PositionedSoundInstance;
 import net.minecraft.client.util.InputUtil;
 import net.minecraft.client.util.InputUtil;
 import net.minecraft.sound.SoundEvents;
 import net.minecraft.sound.SoundEvents;
+import net.minecraft.util.Pair;
 
 
 import java.util.List;
 import java.util.List;
 
 
+@Internal
+@Deprecated
 public class OverlaySearchField extends TextFieldWidget {
 public class OverlaySearchField extends TextFieldWidget {
     
     
     public static boolean isSearching = false;
     public static boolean isSearching = false;
     public long keybindFocusTime = -1;
     public long keybindFocusTime = -1;
     public int keybindFocusKey = -1;
     public int keybindFocusKey = -1;
-    protected long lastClickedTime = -1;
+    protected Pair<Long, Point> lastClickedDetails = null;
     private List<String> history = Lists.newArrayListWithCapacity(100);
     private List<String> history = Lists.newArrayListWithCapacity(100);
     
     
     OverlaySearchField(int x, int y, int width, int height) {
     OverlaySearchField(int x, int y, int width, int height) {
@@ -67,14 +71,25 @@ public class OverlaySearchField extends TextFieldWidget {
             this.font.drawWithShadow(this.font.trimToWidth(this.getSuggestion(), this.getWidth()), x, y, -6250336);
             this.font.drawWithShadow(this.font.trimToWidth(this.getSuggestion(), this.getWidth()), x, y, -6250336);
     }
     }
     
     
+    @SuppressWarnings("deprecation")
     @Override
     @Override
     public void renderBorder() {
     public void renderBorder() {
-        if (!isSearching)
-            super.renderBorder();
-        else if (this.hasBorder()) {
+        boolean hasError = ContainerScreenOverlay.getEntryListWidget().getAllStacks().isEmpty() && !getText().isEmpty();
+        if (isSearching) {
             fill(this.getBounds().x - 1, this.getBounds().y - 1, this.getBounds().x + this.getBounds().width + 1, this.getBounds().y + this.getBounds().height + 1, -852212);
             fill(this.getBounds().x - 1, this.getBounds().y - 1, this.getBounds().x + this.getBounds().width + 1, this.getBounds().y + this.getBounds().height + 1, -852212);
-            fill(this.getBounds().x, this.getBounds().y, this.getBounds().x + this.getBounds().width, this.getBounds().y + this.getBounds().height, -16777216);
+        } else if (hasError) {
+            fill(this.getBounds().x - 1, this.getBounds().y - 1, this.getBounds().x + this.getBounds().width + 1, this.getBounds().y + this.getBounds().height + 1, -43691);
+        } else {
+            super.renderBorder();
+            return;
         }
         }
+        fill(this.getBounds().x, this.getBounds().y, this.getBounds().x + this.getBounds().width, this.getBounds().y + this.getBounds().height, -16777216);
+    }
+    
+    public int getManhattanDistance(Point point1, Point point2) {
+        int e = Math.abs(point1.getX() - point2.getX());
+        int f = Math.abs(point1.getY() - point2.getY());
+        return e + f;
     }
     }
     
     
     @Override
     @Override
@@ -83,14 +98,16 @@ public class OverlaySearchField extends TextFieldWidget {
         if (isVisible() && contains && int_1 == 1)
         if (isVisible() && contains && int_1 == 1)
             setText("");
             setText("");
         if (contains && int_1 == 0)
         if (contains && int_1 == 0)
-            if (lastClickedTime == -1)
-                lastClickedTime = System.currentTimeMillis();
-            else if (System.currentTimeMillis() - lastClickedTime > 700)
-                lastClickedTime = -1;
-            else {
-                lastClickedTime = -1;
+            if (lastClickedDetails == null)
+                lastClickedDetails = new Pair<>(System.currentTimeMillis(), new Point(double_1, double_2));
+            else if (System.currentTimeMillis() - lastClickedDetails.getLeft() > 1500)
+                lastClickedDetails = null;
+            else if (getManhattanDistance(lastClickedDetails.getRight(), new Point(double_1, double_2)) <= 25) {
+                lastClickedDetails = null;
                 isSearching = !isSearching;
                 isSearching = !isSearching;
                 minecraft.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F));
                 minecraft.getSoundManager().play(PositionedSoundInstance.master(SoundEvents.UI_BUTTON_CLICK, 1.0F));
+            } else {
+                lastClickedDetails = new Pair<>(System.currentTimeMillis(), new Point(double_1, double_2));
             }
             }
         return super.mouseClicked(double_1, double_2, int_1);
         return super.mouseClicked(double_1, double_2, int_1);
     }
     }
@@ -140,7 +157,7 @@ public class OverlaySearchField extends TextFieldWidget {
     }
     }
     
     
     @Override
     @Override
-    public void render(int int_1, int int_2, float float_1) {
+    public void render(int mouseX, int mouseY, float delta) {
     }
     }
     
     
 }
 }

+ 5 - 2
src/main/java/me/shedaniel/rei/gui/PreRecipeViewingScreen.java

@@ -11,6 +11,7 @@ import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWi
 import me.shedaniel.clothconfig2.impl.EasingMethod;
 import me.shedaniel.clothconfig2.impl.EasingMethod;
 import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
+import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.gui.config.RecipeScreenType;
 import me.shedaniel.rei.gui.config.RecipeScreenType;
 import me.shedaniel.rei.gui.widget.ButtonWidget;
 import me.shedaniel.rei.gui.widget.ButtonWidget;
 import me.shedaniel.rei.gui.widget.LabelWidget;
 import me.shedaniel.rei.gui.widget.LabelWidget;
@@ -30,6 +31,8 @@ import net.minecraft.util.math.MathHelper;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.List;
 import java.util.List;
 
 
+@Internal
+@Deprecated
 public class PreRecipeViewingScreen extends Screen {
 public class PreRecipeViewingScreen extends Screen {
     
     
     private static final Identifier IDENTIFIER = new Identifier("roughlyenoughitems", "textures/gui/screenshot.png");
     private static final Identifier IDENTIFIER = new Identifier("roughlyenoughitems", "textures/gui/screenshot.png");
@@ -96,9 +99,9 @@ public class PreRecipeViewingScreen extends Screen {
             }
             }
         });
         });
         this.widgets.add(new ScreenTypeSelection(width / 2 - 200 - 5, height / 2 - 112 / 2 - 10, 0));
         this.widgets.add(new ScreenTypeSelection(width / 2 - 200 - 5, height / 2 - 112 / 2 - 10, 0));
-        this.widgets.add(new LabelWidget(new Point(width / 2 - 200 - 5 + 104, height / 2 - 112 / 2 + 115), I18n.translate("config.roughlyenoughitems.recipeScreenType.original")).noShadow().color(-1124073473));
+        this.widgets.add(LabelWidget.create(new Point(width / 2 - 200 - 5 + 104, height / 2 - 112 / 2 + 115), I18n.translate("config.roughlyenoughitems.recipeScreenType.original")).noShadow().color(-1124073473));
         this.widgets.add(new ScreenTypeSelection(width / 2 + 5, height / 2 - 112 / 2 - 10, 112));
         this.widgets.add(new ScreenTypeSelection(width / 2 + 5, height / 2 - 112 / 2 - 10, 112));
-        this.widgets.add(new LabelWidget(new Point(width / 2 + 5 + 104, height / 2 - 112 / 2 + 115), I18n.translate("config.roughlyenoughitems.recipeScreenType.villager")).noShadow().color(-1124073473));
+        this.widgets.add(LabelWidget.create(new Point(width / 2 + 5 + 104, height / 2 - 112 / 2 + 115), I18n.translate("config.roughlyenoughitems.recipeScreenType.villager")).noShadow().color(-1124073473));
         this.children.addAll(widgets);
         this.children.addAll(widgets);
     }
     }
     
     

+ 4 - 1
src/main/java/me/shedaniel/rei/gui/RecipeViewingScreen.java

@@ -11,6 +11,7 @@ import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.rei.api.*;
 import me.shedaniel.rei.api.*;
+import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.gui.widget.*;
 import me.shedaniel.rei.gui.widget.*;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.utils.CollectionUtils;
 import me.shedaniel.rei.utils.CollectionUtils;
@@ -30,6 +31,8 @@ import javax.annotation.Nullable;
 import java.util.*;
 import java.util.*;
 import java.util.function.Supplier;
 import java.util.function.Supplier;
 
 
+@Deprecated
+@Internal
 public class RecipeViewingScreen extends Screen {
 public class RecipeViewingScreen extends Screen {
     
     
     public static final Identifier CHEST_GUI_TEXTURE = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer.png");
     public static final Identifier CHEST_GUI_TEXTURE = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer.png");
@@ -359,7 +362,7 @@ public class RecipeViewingScreen extends Screen {
     
     
     public static class WorkstationSlotWidget extends EntryWidget {
     public static class WorkstationSlotWidget extends EntryWidget {
         public WorkstationSlotWidget(int x, int y, List<EntryStack> widgets) {
         public WorkstationSlotWidget(int x, int y, List<EntryStack> widgets) {
-            super(x, y);
+            super(new Point(x, y));
             entries(widgets);
             entries(widgets);
             noBackground();
             noBackground();
         }
         }

+ 3 - 0
src/main/java/me/shedaniel/rei/gui/VillagerRecipeViewingScreen.java

@@ -14,6 +14,7 @@ import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.rei.api.*;
 import me.shedaniel.rei.api.*;
+import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.gui.entries.RecipeEntry;
 import me.shedaniel.rei.gui.entries.RecipeEntry;
 import me.shedaniel.rei.gui.widget.*;
 import me.shedaniel.rei.gui.widget.*;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.ScreenHelper;
@@ -37,6 +38,8 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Optional;
 
 
+@Deprecated
+@Internal
 public class VillagerRecipeViewingScreen extends Screen {
 public class VillagerRecipeViewingScreen extends Screen {
     
     
     private int tabsPerPage = 8;
     private int tabsPerPage = 8;

+ 16 - 16
src/main/java/me/shedaniel/rei/gui/credits/CreditsEntryListWidget.java

@@ -11,13 +11,13 @@ import net.minecraft.client.gui.DrawableHelper;
 import net.minecraft.text.Text;
 import net.minecraft.text.Text;
 
 
 public class CreditsEntryListWidget extends DynamicNewSmoothScrollingEntryListWidget<CreditsEntryListWidget.CreditsItem> {
 public class CreditsEntryListWidget extends DynamicNewSmoothScrollingEntryListWidget<CreditsEntryListWidget.CreditsItem> {
-
+    
     private boolean inFocus;
     private boolean inFocus;
-
+    
     public CreditsEntryListWidget(MinecraftClient client, int width, int height, int startY, int endY) {
     public CreditsEntryListWidget(MinecraftClient client, int width, int height, int startY, int endY) {
         super(client, width, height, startY, endY, DrawableHelper.BACKGROUND_LOCATION);
         super(client, width, height, startY, endY, DrawableHelper.BACKGROUND_LOCATION);
     }
     }
-
+    
     @Override
     @Override
     public boolean changeFocus(boolean boolean_1) {
     public boolean changeFocus(boolean boolean_1) {
         if (!this.inFocus && this.getItemCount() == 0) {
         if (!this.inFocus && this.getItemCount() == 0) {
@@ -29,58 +29,58 @@ public class CreditsEntryListWidget extends DynamicNewSmoothScrollingEntryListWi
             } else if (this.inFocus && this.getFocused() != null) {
             } else if (this.inFocus && this.getFocused() != null) {
                 this.moveSelection(0);
                 this.moveSelection(0);
             }
             }
-
+            
             return this.inFocus;
             return this.inFocus;
         }
         }
     }
     }
-
+    
     public void creditsClearEntries() {
     public void creditsClearEntries() {
         clearItems();
         clearItems();
     }
     }
-
+    
     private CreditsItem rei_getEntry(int int_1) {
     private CreditsItem rei_getEntry(int int_1) {
         return this.children().get(int_1);
         return this.children().get(int_1);
     }
     }
-
+    
     public void creditsAddEntry(CreditsItem entry) {
     public void creditsAddEntry(CreditsItem entry) {
         addItem(entry);
         addItem(entry);
     }
     }
-
+    
     @Override
     @Override
     public int getItemWidth() {
     public int getItemWidth() {
         return width - 80;
         return width - 80;
     }
     }
-
+    
     @Override
     @Override
     protected int getScrollbarPosition() {
     protected int getScrollbarPosition() {
         return width - 40;
         return width - 40;
     }
     }
-
+    
     public static class CreditsItem extends DynamicNewSmoothScrollingEntryListWidget.Entry<CreditsItem> {
     public static class CreditsItem extends DynamicNewSmoothScrollingEntryListWidget.Entry<CreditsItem> {
         private String text;
         private String text;
-
+        
         public CreditsItem(Text textComponent) {
         public CreditsItem(Text textComponent) {
             this(textComponent.asFormattedString());
             this(textComponent.asFormattedString());
         }
         }
-
+        
         public CreditsItem(String text) {
         public CreditsItem(String text) {
             this.text = text;
             this.text = text;
         }
         }
-
+        
         @Override
         @Override
         public void render(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
         public void render(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
             MinecraftClient.getInstance().textRenderer.drawWithShadow(text, x + 5, y + 5, -1);
             MinecraftClient.getInstance().textRenderer.drawWithShadow(text, x + 5, y + 5, -1);
         }
         }
-
+        
         @Override
         @Override
         public int getItemHeight() {
         public int getItemHeight() {
             return 12;
             return 12;
         }
         }
-
+        
         @Override
         @Override
         public boolean changeFocus(boolean boolean_1) {
         public boolean changeFocus(boolean boolean_1) {
             return false;
             return false;
         }
         }
     }
     }
-
+    
 }
 }

+ 8 - 8
src/main/java/me/shedaniel/rei/gui/toast/CopyRecipeIdentifierToast.java

@@ -14,21 +14,21 @@ import net.minecraft.util.Identifier;
 import javax.annotation.Nullable;
 import javax.annotation.Nullable;
 
 
 public class CopyRecipeIdentifierToast implements Toast {
 public class CopyRecipeIdentifierToast implements Toast {
-
+    
     protected static final Identifier TOASTS_TEX = new Identifier("roughlyenoughitems", "textures/gui/toasts.png");
     protected static final Identifier TOASTS_TEX = new Identifier("roughlyenoughitems", "textures/gui/toasts.png");
     private String title;
     private String title;
     private String subtitle;
     private String subtitle;
     private long startTime;
     private long startTime;
-
+    
     public CopyRecipeIdentifierToast(String title, @Nullable String subtitleNullable) {
     public CopyRecipeIdentifierToast(String title, @Nullable String subtitleNullable) {
         this.title = title;
         this.title = title;
         this.subtitle = subtitleNullable;
         this.subtitle = subtitleNullable;
     }
     }
-
+    
     public static void addToast(String title, @Nullable String subtitleNullable) {
     public static void addToast(String title, @Nullable String subtitleNullable) {
         MinecraftClient.getInstance().getToastManager().add(new CopyRecipeIdentifierToast(title, subtitleNullable));
         MinecraftClient.getInstance().getToastManager().add(new CopyRecipeIdentifierToast(title, subtitleNullable));
     }
     }
-
+    
     @Override
     @Override
     public Visibility draw(ToastManager toastManager, long var2) {
     public Visibility draw(ToastManager toastManager, long var2) {
         toastManager.getGame().getTextureManager().bindTexture(TOASTS_TEX);
         toastManager.getGame().getTextureManager().bindTexture(TOASTS_TEX);
@@ -40,17 +40,17 @@ public class CopyRecipeIdentifierToast implements Toast {
             toastManager.getGame().textRenderer.draw(this.title, 18.0F, 7.0F, 11141120);
             toastManager.getGame().textRenderer.draw(this.title, 18.0F, 7.0F, 11141120);
             toastManager.getGame().textRenderer.draw(this.subtitle, 18.0F, 18.0F, -16777216);
             toastManager.getGame().textRenderer.draw(this.subtitle, 18.0F, 18.0F, -16777216);
         }
         }
-
+        
         return var2 - this.startTime < 5000L ? Visibility.SHOW : Visibility.HIDE;
         return var2 - this.startTime < 5000L ? Visibility.SHOW : Visibility.HIDE;
     }
     }
-
+    
     @Override
     @Override
     public Object getType() {
     public Object getType() {
         return Type.THIS_IS_SURE_A_TYPE;
         return Type.THIS_IS_SURE_A_TYPE;
     }
     }
-
+    
     public enum Type {
     public enum Type {
         THIS_IS_SURE_A_TYPE
         THIS_IS_SURE_A_TYPE
     }
     }
-
+    
 }
 }

+ 3 - 0
src/main/java/me/shedaniel/rei/gui/widget/AutoCraftingButtonWidget.java

@@ -11,6 +11,7 @@ import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.rei.api.*;
 import me.shedaniel.rei.api.*;
+import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.gui.toast.CopyRecipeIdentifierToast;
 import me.shedaniel.rei.gui.toast.CopyRecipeIdentifierToast;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.ScreenHelper;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.MinecraftClient;
@@ -27,6 +28,8 @@ import java.util.UUID;
 import java.util.function.Supplier;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
+@Internal
+@Deprecated
 public class AutoCraftingButtonWidget extends ButtonWidget {
 public class AutoCraftingButtonWidget extends ButtonWidget {
     
     
     private static final Lazy<Boolean> IS_YOG = new Lazy(() -> {
     private static final Lazy<Boolean> IS_YOG = new Lazy(() -> {

+ 3 - 0
src/main/java/me/shedaniel/rei/gui/widget/ButtonWidget.java

@@ -9,6 +9,7 @@ import com.mojang.blaze3d.systems.RenderSystem;
 import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.rei.api.ConfigObject;
 import me.shedaniel.rei.api.ConfigObject;
+import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.ScreenHelper;
 import net.minecraft.client.gui.Element;
 import net.minecraft.client.gui.Element;
 import net.minecraft.client.sound.PositionedSoundInstance;
 import net.minecraft.client.sound.PositionedSoundInstance;
@@ -22,6 +23,8 @@ import java.util.List;
 import java.util.Objects;
 import java.util.Objects;
 import java.util.Optional;
 import java.util.Optional;
 
 
+@Internal
+@Deprecated
 public abstract class ButtonWidget extends WidgetWithBounds {
 public abstract class ButtonWidget extends WidgetWithBounds {
     
     
     protected static final Identifier BUTTON_LOCATION = new Identifier("roughlyenoughitems", "textures/gui/button.png");
     protected static final Identifier BUTTON_LOCATION = new Identifier("roughlyenoughitems", "textures/gui/button.png");

+ 27 - 0
src/main/java/me/shedaniel/rei/gui/widget/ClickableActionedLabelWidget.java

@@ -0,0 +1,27 @@
+/*
+ * Roughly Enough Items by Danielshe.
+ * Licensed under the MIT License.
+ */
+
+package me.shedaniel.rei.gui.widget;
+
+import me.shedaniel.math.api.Point;
+import me.shedaniel.rei.api.annotations.Internal;
+
+import java.util.function.Consumer;
+
+@Deprecated
+@Internal
+public class ClickableActionedLabelWidget extends ClickableLabelWidget {
+    private Consumer<ClickableLabelWidget> onClicked;
+    
+    ClickableActionedLabelWidget(Point point, String text, Consumer<ClickableLabelWidget> onClicked) {
+        super(point, text);
+        this.onClicked = onClicked;
+    }
+    
+    @Override
+    public void onLabelClicked() {
+        onClicked.accept(this);
+    }
+}

+ 8 - 8
src/main/java/me/shedaniel/rei/gui/widget/ClickableLabelWidget.java

@@ -8,8 +8,6 @@ package me.shedaniel.rei.gui.widget;
 import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Point;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.ScreenHelper;
 
 
-import java.util.Optional;
-
 public abstract class ClickableLabelWidget extends LabelWidget {
 public abstract class ClickableLabelWidget extends LabelWidget {
     
     
     public boolean focused;
     public boolean focused;
@@ -32,6 +30,7 @@ public abstract class ClickableLabelWidget extends LabelWidget {
         clickable(clickable);
         clickable(clickable);
     }
     }
     
     
+    @Deprecated
     public ClickableLabelWidget(Point point, String text) {
     public ClickableLabelWidget(Point point, String text) {
         super(point, text);
         super(point, text);
         this.hoveredColor = ScreenHelper.isDarkModeEnabled() ? -1 : 0xFF66FFCC;
         this.hoveredColor = ScreenHelper.isDarkModeEnabled() ? -1 : 0xFF66FFCC;
@@ -69,11 +68,16 @@ public abstract class ClickableLabelWidget extends LabelWidget {
             else
             else
                 font.draw(getText(), pos.x, pos.y, color);
                 font.draw(getText(), pos.x, pos.y, color);
         }
         }
-        if (isClickable() && getTooltips().isPresent())
+        drawTooltips(mouseX, mouseY);
+    }
+    
+    @Override
+    protected void drawTooltips(int mouseX, int mouseY) {
+        if (getTooltips().isPresent())
             if (!focused && containsMouse(mouseX, mouseY))
             if (!focused && containsMouse(mouseX, mouseY))
                 ScreenHelper.getLastOverlay().addTooltip(QueuedTooltip.create(getTooltips().get().split("\n")));
                 ScreenHelper.getLastOverlay().addTooltip(QueuedTooltip.create(getTooltips().get().split("\n")));
             else if (focused)
             else if (focused)
-                ScreenHelper.getLastOverlay().addTooltip(QueuedTooltip.create(pos, getTooltips().get().split("\n")));
+                ScreenHelper.getLastOverlay().addTooltip(QueuedTooltip.create(getPosition(), getTooltips().get().split("\n")));
     }
     }
     
     
     public int getHoveredColor() {
     public int getHoveredColor() {
@@ -89,10 +93,6 @@ public abstract class ClickableLabelWidget extends LabelWidget {
         return false;
         return false;
     }
     }
     
     
-    public Optional<String> getTooltips() {
-        return Optional.empty();
-    }
-    
     @Override
     @Override
     public boolean keyPressed(int int_1, int int_2, int int_3) {
     public boolean keyPressed(int int_1, int int_2, int int_3) {
         if (!isClickable() || !focused)
         if (!isClickable() || !focused)

+ 3 - 0
src/main/java/me/shedaniel/rei/gui/widget/CraftableToggleButtonWidget.java

@@ -8,6 +8,7 @@ package me.shedaniel.rei.gui.widget;
 import com.mojang.blaze3d.systems.RenderSystem;
 import com.mojang.blaze3d.systems.RenderSystem;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.rei.api.ConfigManager;
 import me.shedaniel.rei.api.ConfigManager;
+import me.shedaniel.rei.api.annotations.Internal;
 import net.minecraft.block.Blocks;
 import net.minecraft.block.Blocks;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.render.item.ItemRenderer;
 import net.minecraft.client.render.item.ItemRenderer;
@@ -17,6 +18,8 @@ import net.minecraft.util.Identifier;
 
 
 import java.util.Optional;
 import java.util.Optional;
 
 
+@Deprecated
+@Internal
 public abstract class CraftableToggleButtonWidget extends ButtonWidget {
 public abstract class CraftableToggleButtonWidget extends ButtonWidget {
     
     
     public static final Identifier CHEST_GUI_TEXTURE = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer.png");
     public static final Identifier CHEST_GUI_TEXTURE = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer.png");

+ 3 - 0
src/main/java/me/shedaniel/rei/gui/widget/DraggableWidget.java

@@ -8,10 +8,13 @@ package me.shedaniel.rei.gui.widget;
 import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.math.impl.PointHelper;
+import me.shedaniel.rei.api.annotations.Internal;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.Element;
 import net.minecraft.client.gui.Element;
 import net.minecraft.client.util.Window;
 import net.minecraft.client.util.Window;
 
 
+@Deprecated
+@Internal
 public abstract class DraggableWidget extends WidgetWithBounds {
 public abstract class DraggableWidget extends WidgetWithBounds {
     
     
     public boolean dragged = false;
     public boolean dragged = false;

+ 100 - 17
src/main/java/me/shedaniel/rei/gui/widget/EntryListWidget.java

@@ -15,6 +15,7 @@ import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
 import me.shedaniel.rei.api.*;
 import me.shedaniel.rei.api.*;
+import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.gui.ContainerScreenOverlay;
 import me.shedaniel.rei.gui.ContainerScreenOverlay;
 import me.shedaniel.rei.gui.config.ItemListOrdering;
 import me.shedaniel.rei.gui.config.ItemListOrdering;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.ScreenHelper;
@@ -37,14 +38,12 @@ import net.minecraft.util.math.MathHelper;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.commons.lang3.StringUtils;
 
 
 import javax.annotation.Nullable;
 import javax.annotation.Nullable;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
-import java.util.Locale;
+import java.util.*;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.function.Supplier;
 import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
+@Internal
 public class EntryListWidget extends WidgetWithBounds {
 public class EntryListWidget extends WidgetWithBounds {
     
     
     static final Supplier<Boolean> RENDER_ENCHANTMENT_GLINT = ConfigObject.getInstance()::doesRenderEntryEnchantmentGlint;
     static final Supplier<Boolean> RENDER_ENCHANTMENT_GLINT = ConfigObject.getInstance()::doesRenderEntryEnchantmentGlint;
@@ -72,6 +71,7 @@ public class EntryListWidget extends WidgetWithBounds {
     private List<EntryStack> allStacks = null;
     private List<EntryStack> allStacks = null;
     private List<EntryStack> favorites = null;
     private List<EntryStack> favorites = null;
     private List<EntryListEntry> entries = Collections.emptyList();
     private List<EntryListEntry> entries = Collections.emptyList();
+    private List<Widget> renders = Collections.emptyList();
     private List<Widget> widgets = Collections.emptyList();
     private List<Widget> widgets = Collections.emptyList();
     @SuppressWarnings("deprecation") private List<SearchArgument.SearchArguments> lastSearchArguments = Collections.emptyList();
     @SuppressWarnings("deprecation") private List<SearchArgument.SearchArguments> lastSearchArguments = Collections.emptyList();
     private boolean draggingScrollBar = false;
     private boolean draggingScrollBar = false;
@@ -324,16 +324,55 @@ public class EntryListWidget extends WidgetWithBounds {
         } else {
         } else {
             if (debugTime) {
             if (debugTime) {
                 int size = 0;
                 int size = 0;
-                long totalTimeStart = System.nanoTime();
                 long time = 0;
                 long time = 0;
-                for (Widget widget : widgets) {
-                    if (widget instanceof EntryListEntry) {
+                for (Widget widget : renders) {
+                    widget.render(mouseX, mouseY, delta);
+                }
+                long totalTimeStart = System.nanoTime();
+                if (ConfigObject.getInstance().doesFastEntryRendering()) {
+                    for (Map.Entry<? extends Class<? extends EntryStack>, List<EntryListEntry>> entry : entries.stream().collect(Collectors.groupingBy(entryListEntry -> entryListEntry.getCurrentEntry().getClass())).entrySet()) {
+                        List<EntryListEntry> list = entry.getValue();
+                        if (list.isEmpty())
+                            continue;
+                        EntryListEntry firstWidget = list.get(0);
+                        EntryStack first = firstWidget.getCurrentEntry();
+                        if (first instanceof OptimalEntryStack) {
+                            OptimalEntryStack firstStack = (OptimalEntryStack) first;
+                            firstStack.optimisedRenderStart(delta);
+                            size += list.size();
+                            long l = System.nanoTime();
+                            for (EntryListEntry listEntry : list) {
+                                EntryStack currentEntry = listEntry.getCurrentEntry();
+                                currentEntry.setZ(100);
+                                listEntry.drawBackground(mouseX, mouseY, delta);
+                                ((OptimalEntryStack) currentEntry).optimisedRenderBase(listEntry.getInnerBounds(), mouseX, mouseY, delta);
+                            }
+                            for (EntryListEntry listEntry : list) {
+                                EntryStack currentEntry = listEntry.getCurrentEntry();
+                                ((OptimalEntryStack) currentEntry).optimisedRenderOverlay(listEntry.getInnerBounds(), mouseX, mouseY, delta);
+                                if (listEntry.containsMouse(mouseX, mouseY)) {
+                                    listEntry.queueTooltip(mouseX, mouseY, delta);
+                                    listEntry.drawHighlighted(mouseX, mouseY, delta);
+                                }
+                            }
+                            time += (System.nanoTime() - l);
+                            firstStack.optimisedRenderEnd(delta);
+                        } else {
+                            for (EntryListEntry listEntry : list) {
+                                size++;
+                                long l = System.nanoTime();
+                                listEntry.render(mouseX, mouseY, delta);
+                                time += (System.nanoTime() - l);
+                            }
+                        }
+                    }
+                } else {
+                    for (EntryListEntry entry : entries) {
                         size++;
                         size++;
                         long l = System.nanoTime();
                         long l = System.nanoTime();
-                        widget.render(mouseX, mouseY, delta);
+                        entry.render(mouseX, mouseY, delta);
                         time += (System.nanoTime() - l);
                         time += (System.nanoTime() - l);
-                    } else
-                        widget.render(mouseX, mouseY, delta);
+                    }
                 }
                 }
                 long totalTime = System.nanoTime() - totalTimeStart;
                 long totalTime = System.nanoTime() - totalTimeStart;
                 int z = getZ();
                 int z = getZ();
@@ -349,9 +388,45 @@ public class EntryListWidget extends WidgetWithBounds {
                 immediate.draw();
                 immediate.draw();
                 setZ(z);
                 setZ(z);
             } else {
             } else {
-                for (Widget widget : widgets) {
+                for (Widget widget : renders) {
                     widget.render(mouseX, mouseY, delta);
                     widget.render(mouseX, mouseY, delta);
                 }
                 }
+                if (ConfigObject.getInstance().doesFastEntryRendering()) {
+                    for (Map.Entry<? extends Class<? extends EntryStack>, List<EntryListEntry>> entry : entries.stream().collect(Collectors.groupingBy(entryListEntry -> entryListEntry.getCurrentEntry().getClass())).entrySet()) {
+                        List<EntryListEntry> list = entry.getValue();
+                        if (list.isEmpty())
+                            continue;
+                        EntryListEntry firstWidget = list.get(0);
+                        EntryStack first = firstWidget.getCurrentEntry();
+                        if (first instanceof OptimalEntryStack) {
+                            OptimalEntryStack firstStack = (OptimalEntryStack) first;
+                            firstStack.optimisedRenderStart(delta);
+                            for (EntryListEntry listEntry : list) {
+                                EntryStack currentEntry = listEntry.getCurrentEntry();
+                                currentEntry.setZ(100);
+                                listEntry.drawBackground(mouseX, mouseY, delta);
+                                ((OptimalEntryStack) currentEntry).optimisedRenderBase(listEntry.getInnerBounds(), mouseX, mouseY, delta);
+                            }
+                            for (EntryListEntry listEntry : list) {
+                                EntryStack currentEntry = listEntry.getCurrentEntry();
+                                ((OptimalEntryStack) currentEntry).optimisedRenderOverlay(listEntry.getInnerBounds(), mouseX, mouseY, delta);
+                                if (listEntry.containsMouse(mouseX, mouseY)) {
+                                    listEntry.queueTooltip(mouseX, mouseY, delta);
+                                    listEntry.drawHighlighted(mouseX, mouseY, delta);
+                                }
+                            }
+                            firstStack.optimisedRenderEnd(delta);
+                        } else {
+                            for (EntryListEntry listEntry : list) {
+                                listEntry.render(mouseX, mouseY, delta);
+                            }
+                        }
+                    }
+                } else {
+                    for (EntryListEntry listEntry : entries) {
+                        listEntry.render(mouseX, mouseY, delta);
+                    }
+                }
             }
             }
         }
         }
         if (containsMouse(mouseX, mouseY) && ClientHelper.getInstance().isCheating() && !minecraft.player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.hasPermissionToUsePackets())
         if (containsMouse(mouseX, mouseY) && ClientHelper.getInstance().isCheating() && !minecraft.player.inventory.getCursorStack().isEmpty() && RoughlyEnoughItemsCore.hasPermissionToUsePackets())
@@ -464,6 +539,7 @@ public class EntryListWidget extends WidgetWithBounds {
     public void updateEntriesPosition() {
     public void updateEntriesPosition() {
         this.innerBounds = updateInnerBounds(bounds);
         this.innerBounds = updateInnerBounds(bounds);
         if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
         if (!ConfigObject.getInstance().isEntryListWidgetScrolled()) {
+            this.renders = Lists.newArrayList();
             page = Math.max(page, 0);
             page = Math.max(page, 0);
             List<EntryListEntry> entries = Lists.newArrayList();
             List<EntryListEntry> entries = Lists.newArrayList();
             int width = innerBounds.width / entrySize();
             int width = innerBounds.width / entrySize();
@@ -484,12 +560,11 @@ public class EntryListWidget extends WidgetWithBounds {
                 entries.get(i + Math.max(0, numberForFavorites - page * entries.size())).isFavorites = false;
                 entries.get(i + Math.max(0, numberForFavorites - page * entries.size())).isFavorites = false;
             }
             }
             this.entries = entries;
             this.entries = entries;
-            this.widgets = Lists.newArrayList(entries);
             if (numberForFavorites > 0) {
             if (numberForFavorites > 0) {
                 int skippedFavorites = page * (entries.size() - width);
                 int skippedFavorites = page * (entries.size() - width);
                 int j = 0;
                 int j = 0;
                 if (skippedFavorites < favorites.size()) {
                 if (skippedFavorites < favorites.size()) {
-                    widgets.add(new LabelWidget(new Point(innerBounds.x + 2, innerBounds.y + 6), I18n.translate("text.rei.favorites")).leftAligned());
+                    renders.add(LabelWidget.create(new Point(innerBounds.x + 2, innerBounds.y + 6), I18n.translate("text.rei.favorites")).leftAligned());
                     j += width;
                     j += width;
                 }
                 }
                 List<EntryStack> subFavoritesList = favorites.stream().skip(skippedFavorites).limit(Math.max(0, entries.size() - width)).collect(Collectors.toList());
                 List<EntryStack> subFavoritesList = favorites.stream().skip(skippedFavorites).limit(Math.max(0, entries.size() - width)).collect(Collectors.toList());
@@ -499,6 +574,8 @@ public class EntryListWidget extends WidgetWithBounds {
                     j++;
                     j++;
                 }
                 }
             }
             }
+            this.widgets = Lists.newArrayList(renders);
+            this.widgets.addAll(entries);
         } else {
         } else {
             page = 0;
             page = 0;
             int width = innerBounds.width / entrySize();
             int width = innerBounds.width / entrySize();
@@ -519,7 +596,8 @@ public class EntryListWidget extends WidgetWithBounds {
                 }
                 }
             }
             }
             this.entries = entries;
             this.entries = entries;
-            this.widgets = Collections.unmodifiableList(entries);
+            this.widgets = Lists.newArrayList(renders);
+            this.widgets.addAll(entries);
         }
         }
         FavoritesListWidget favoritesListWidget = ContainerScreenOverlay.getFavoritesListWidget();
         FavoritesListWidget favoritesListWidget = ContainerScreenOverlay.getFavoritesListWidget();
         if (favoritesListWidget != null)
         if (favoritesListWidget != null)
@@ -741,24 +819,29 @@ public class EntryListWidget extends WidgetWithBounds {
         private boolean isFavorites;
         private boolean isFavorites;
         
         
         private EntryListEntry(int x, int y) {
         private EntryListEntry(int x, int y) {
-            super(x, y);
+            super(new Point(x, y));
             this.backupY = y;
             this.backupY = y;
             getBounds().width = getBounds().height = entrySize();
             getBounds().width = getBounds().height = entrySize();
         }
         }
         
         
+        @Override
+        public void drawBackground(int mouseX, int mouseY, float delta) {
+            super.drawBackground(mouseX, mouseY, delta);
+        }
+        
         @Override
         @Override
         public boolean containsMouse(double mouseX, double mouseY) {
         public boolean containsMouse(double mouseX, double mouseY) {
             return super.containsMouse(mouseX, mouseY) && bounds.contains(mouseX, mouseY);
             return super.containsMouse(mouseX, mouseY) && bounds.contains(mouseX, mouseY);
         }
         }
         
         
         @Override
         @Override
-        protected void drawHighlighted(int mouseX, int mouseY, float delta) {
+        public void drawHighlighted(int mouseX, int mouseY, float delta) {
             if (getCurrentEntry().getType() != EntryStack.Type.EMPTY)
             if (getCurrentEntry().getType() != EntryStack.Type.EMPTY)
                 super.drawHighlighted(mouseX, mouseY, delta);
                 super.drawHighlighted(mouseX, mouseY, delta);
         }
         }
         
         
         @Override
         @Override
-        protected void queueTooltip(int mouseX, int mouseY, float delta) {
+        public void queueTooltip(int mouseX, int mouseY, float delta) {
             if (!ClientHelper.getInstance().isCheating() || minecraft.player.inventory.getCursorStack().isEmpty()) {
             if (!ClientHelper.getInstance().isCheating() || minecraft.player.inventory.getCursorStack().isEmpty()) {
                 super.queueTooltip(mouseX, mouseY, delta);
                 super.queueTooltip(mouseX, mouseY, delta);
             }
             }

+ 26 - 9
src/main/java/me/shedaniel/rei/gui/widget/EntryWidget.java

@@ -7,6 +7,7 @@ package me.shedaniel.rei.gui.widget;
 
 
 import com.mojang.blaze3d.systems.RenderSystem;
 import com.mojang.blaze3d.systems.RenderSystem;
 import me.shedaniel.clothconfig2.api.ModifierKeyCode;
 import me.shedaniel.clothconfig2.api.ModifierKeyCode;
+import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.rei.api.ClientHelper;
 import me.shedaniel.rei.api.ClientHelper;
@@ -39,12 +40,20 @@ public class EntryWidget extends WidgetWithBounds {
     private List<EntryStack> entryStacks;
     private List<EntryStack> entryStacks;
     
     
     protected EntryWidget(int x, int y) {
     protected EntryWidget(int x, int y) {
-        this.bounds = new Rectangle(x - 1, y - 1, 18, 18);
+        this(new Point(x, y));
+    }
+    
+    protected EntryWidget(Point point) {
+        this.bounds = new Rectangle(point.x - 1, point.y - 1, 18, 18);
         this.entryStacks = new ArrayList<>();
         this.entryStacks = new ArrayList<>();
     }
     }
     
     
     public static EntryWidget create(int x, int y) {
     public static EntryWidget create(int x, int y) {
-        return new EntryWidget(x, y);
+        return create(new Point(x, y));
+    }
+    
+    public static EntryWidget create(Point point) {
+        return new EntryWidget(point);
     }
     }
     
     
     public EntryWidget disableInteractions() {
     public EntryWidget disableInteractions() {
@@ -131,23 +140,31 @@ public class EntryWidget extends WidgetWithBounds {
     
     
     @Override
     @Override
     public void render(int mouseX, int mouseY, float delta) {
     public void render(int mouseX, int mouseY, float delta) {
-        if (background) {
-            drawBackground(mouseX, mouseY, delta);
-        }
+        drawBackground(mouseX, mouseY, delta);
         drawCurrentEntry(mouseX, mouseY, delta);
         drawCurrentEntry(mouseX, mouseY, delta);
         
         
         boolean highlighted = containsMouse(mouseX, mouseY);
         boolean highlighted = containsMouse(mouseX, mouseY);
-        if (tooltips && highlighted) {
+        if (hasTooltips() && highlighted) {
             queueTooltip(mouseX, mouseY, delta);
             queueTooltip(mouseX, mouseY, delta);
         }
         }
-        if (highlight && highlighted) {
+        if (hasHighlight() && highlighted) {
             drawHighlighted(mouseX, mouseY, delta);
             drawHighlighted(mouseX, mouseY, delta);
         }
         }
     }
     }
     
     
+    public final boolean hasTooltips() {
+        return tooltips;
+    }
+    
+    public final boolean hasHighlight() {
+        return highlight;
+    }
+    
     protected void drawBackground(int mouseX, int mouseY, float delta) {
     protected void drawBackground(int mouseX, int mouseY, float delta) {
-        minecraft.getTextureManager().bindTexture(ScreenHelper.isDarkModeEnabled() ? RECIPE_GUI_DARK : RECIPE_GUI);
-        blit(bounds.x, bounds.y, 0, 222, bounds.width, bounds.height);
+        if (background) {
+            minecraft.getTextureManager().bindTexture(ScreenHelper.isDarkModeEnabled() ? RECIPE_GUI_DARK : RECIPE_GUI);
+            blit(bounds.x, bounds.y, 0, 222, bounds.width, bounds.height);
+        }
     }
     }
     
     
     protected void drawCurrentEntry(int mouseX, int mouseY, float delta) {
     protected void drawCurrentEntry(int mouseX, int mouseY, float delta) {

+ 4 - 1
src/main/java/me/shedaniel/rei/gui/widget/FavoritesListWidget.java

@@ -10,9 +10,11 @@ import com.mojang.blaze3d.systems.RenderSystem;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.ClothConfigInitializer;
 import me.shedaniel.clothconfig2.api.ScissorsHandler;
 import me.shedaniel.clothconfig2.api.ScissorsHandler;
 import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWidget;
 import me.shedaniel.clothconfig2.gui.widget.DynamicNewSmoothScrollingEntryListWidget;
+import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.rei.api.*;
 import me.shedaniel.rei.api.*;
+import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.gui.config.ItemListOrdering;
 import me.shedaniel.rei.gui.config.ItemListOrdering;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.utils.CollectionUtils;
 import me.shedaniel.rei.utils.CollectionUtils;
@@ -28,6 +30,7 @@ import java.util.List;
 
 
 import static me.shedaniel.rei.gui.widget.EntryListWidget.*;
 import static me.shedaniel.rei.gui.widget.EntryListWidget.*;
 
 
+@Internal
 public class FavoritesListWidget extends WidgetWithBounds {
 public class FavoritesListWidget extends WidgetWithBounds {
     protected double target;
     protected double target;
     protected double scroll;
     protected double scroll;
@@ -318,7 +321,7 @@ public class FavoritesListWidget extends WidgetWithBounds {
         private int backupY;
         private int backupY;
         
         
         private EntryListEntry(int x, int y) {
         private EntryListEntry(int x, int y) {
-            super(x, y);
+            super(new Point(x, y));
             this.backupY = y;
             this.backupY = y;
             getBounds().width = getBounds().height = entrySize();
             getBounds().width = getBounds().height = entrySize();
         }
         }

+ 27 - 0
src/main/java/me/shedaniel/rei/gui/widget/LabelWidget.java

@@ -12,6 +12,9 @@ import net.minecraft.client.gui.Element;
 
 
 import java.util.Collections;
 import java.util.Collections;
 import java.util.List;
 import java.util.List;
+import java.util.Optional;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
 
 
 public class LabelWidget extends WidgetWithBounds {
 public class LabelWidget extends WidgetWithBounds {
     
     
@@ -20,18 +23,33 @@ public class LabelWidget extends WidgetWithBounds {
     private int defaultColor;
     private int defaultColor;
     private boolean hasShadows = true;
     private boolean hasShadows = true;
     private boolean centered = true;
     private boolean centered = true;
+    private Supplier<String> tooltipSupplier;
     
     
     @Deprecated
     @Deprecated
     public LabelWidget(int x, int y, String text) {
     public LabelWidget(int x, int y, String text) {
         this(new Point(x, y), text);
         this(new Point(x, y), text);
     }
     }
     
     
+    @Deprecated
     public LabelWidget(Point point, String text) {
     public LabelWidget(Point point, String text) {
         this.pos = point;
         this.pos = point;
         this.text = text;
         this.text = text;
         this.defaultColor = ScreenHelper.isDarkModeEnabled() ? 0xFFBBBBBB : -1;
         this.defaultColor = ScreenHelper.isDarkModeEnabled() ? 0xFFBBBBBB : -1;
     }
     }
     
     
+    public static LabelWidget create(Point point, String text) {
+        return new LabelWidget(point, text);
+    }
+    
+    public static ClickableLabelWidget createClickable(Point point, String text, Consumer<ClickableLabelWidget> onClicked) {
+        return new ClickableActionedLabelWidget(point, text, onClicked);
+    }
+    
+    public LabelWidget tooltip(Supplier<String> tooltipSupplier) {
+        this.tooltipSupplier = tooltipSupplier;
+        return this;
+    }
+    
     public boolean isCentered() {
     public boolean isCentered() {
         return centered;
         return centered;
     }
     }
@@ -94,6 +112,10 @@ public class LabelWidget extends WidgetWithBounds {
         return this;
         return this;
     }
     }
     
     
+    public Optional<String> getTooltips() {
+        return Optional.ofNullable(tooltipSupplier).map(Supplier::get);
+    }
+    
     @Override
     @Override
     public Rectangle getBounds() {
     public Rectangle getBounds() {
         int width = font.getStringWidth(text);
         int width = font.getStringWidth(text);
@@ -125,4 +147,9 @@ public class LabelWidget extends WidgetWithBounds {
         }
         }
     }
     }
     
     
+    protected void drawTooltips(int mouseX, int mouseY) {
+        if (getTooltips().isPresent())
+            if (containsMouse(mouseX, mouseY))
+                ScreenHelper.getLastOverlay().addTooltip(QueuedTooltip.create(getTooltips().get().split("\n")));
+    }
 }
 }

+ 6 - 0
src/main/java/me/shedaniel/rei/gui/widget/RecipeArrowWidget.java

@@ -5,6 +5,7 @@
 
 
 package me.shedaniel.rei.gui.widget;
 package me.shedaniel.rei.gui.widget;
 
 
+import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.rei.plugin.DefaultPlugin;
 import me.shedaniel.rei.plugin.DefaultPlugin;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.MinecraftClient;
@@ -19,12 +20,17 @@ public class RecipeArrowWidget extends WidgetWithBounds {
     private int x, y;
     private int x, y;
     private boolean animated;
     private boolean animated;
     
     
+    @Deprecated
     public RecipeArrowWidget(int x, int y, boolean animated) {
     public RecipeArrowWidget(int x, int y, boolean animated) {
         this.x = x;
         this.x = x;
         this.y = y;
         this.y = y;
         this.animated = animated;
         this.animated = animated;
     }
     }
     
     
+    public static RecipeArrowWidget create(Point point, boolean animated) {
+        return new RecipeArrowWidget(point.x, point.y, animated);
+    }
+    
     @Override
     @Override
     public Rectangle getBounds() {
     public Rectangle getBounds() {
         return new Rectangle(x, y, 24, 17);
         return new Rectangle(x, y, 24, 17);

+ 6 - 4
src/main/java/me/shedaniel/rei/gui/widget/RecipeChoosePageWidget.java

@@ -9,6 +9,7 @@ import com.google.common.collect.Lists;
 import com.mojang.blaze3d.systems.RenderSystem;
 import com.mojang.blaze3d.systems.RenderSystem;
 import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
+import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.gui.RecipeViewingScreen;
 import me.shedaniel.rei.gui.RecipeViewingScreen;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.ScreenHelper;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.MinecraftClient;
@@ -20,6 +21,8 @@ import java.util.Collections;
 import java.util.List;
 import java.util.List;
 import java.util.Optional;
 import java.util.Optional;
 
 
+@Deprecated
+@Internal
 public class RecipeChoosePageWidget extends DraggableWidget {
 public class RecipeChoosePageWidget extends DraggableWidget {
     
     
     private int currentPage;
     private int currentPage;
@@ -101,13 +104,12 @@ public class RecipeChoosePageWidget extends DraggableWidget {
         int width = font.getStringWidth(endString);
         int width = font.getStringWidth(endString);
         this.widgets.add(textFieldWidget = new TextFieldWidget(bounds.x + 7, bounds.y + 16, bounds.width - width - 12, 18));
         this.widgets.add(textFieldWidget = new TextFieldWidget(bounds.x + 7, bounds.y + 16, bounds.width - width - 12, 18));
         textFieldWidget.setMaxLength(10000);
         textFieldWidget.setMaxLength(10000);
-        textFieldWidget.stripInvaild = s -> {
+        textFieldWidget.stripInvalid = s -> {
             StringBuilder stringBuilder_1 = new StringBuilder();
             StringBuilder stringBuilder_1 = new StringBuilder();
             char[] var2 = s.toCharArray();
             char[] var2 = s.toCharArray();
             int var3 = var2.length;
             int var3 = var2.length;
             
             
-            for (int var4 = 0; var4 < var3; ++var4) {
-                char char_1 = var2[var4];
+            for (char char_1 : var2) {
                 if (Character.isDigit(char_1))
                 if (Character.isDigit(char_1))
                     stringBuilder_1.append(char_1);
                     stringBuilder_1.append(char_1);
             }
             }
@@ -170,7 +172,7 @@ public class RecipeChoosePageWidget extends DraggableWidget {
     public Optional<Integer> getIntFromString(String s) {
     public Optional<Integer> getIntFromString(String s) {
         try {
         try {
             return Optional.of(Integer.valueOf(s));
             return Optional.of(Integer.valueOf(s));
-        } catch (Exception e) {
+        } catch (Exception ignored) {
         }
         }
         return Optional.empty();
         return Optional.empty();
     }
     }

+ 5 - 3
src/main/java/me/shedaniel/rei/gui/widget/TabWidget.java

@@ -9,6 +9,7 @@ import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.rei.api.ClientHelper;
 import me.shedaniel.rei.api.ClientHelper;
 import me.shedaniel.rei.api.EntryStack;
 import me.shedaniel.rei.api.EntryStack;
 import me.shedaniel.rei.api.RecipeCategory;
 import me.shedaniel.rei.api.RecipeCategory;
+import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.impl.ScreenHelper;
 import me.shedaniel.rei.impl.ScreenHelper;
 import net.minecraft.util.Formatting;
 import net.minecraft.util.Formatting;
 import net.minecraft.util.Identifier;
 import net.minecraft.util.Identifier;
@@ -16,6 +17,8 @@ import net.minecraft.util.Identifier;
 import java.util.Collections;
 import java.util.Collections;
 import java.util.List;
 import java.util.List;
 
 
+@Deprecated
+@Internal
 public class TabWidget extends WidgetWithBounds {
 public class TabWidget extends WidgetWithBounds {
     
     
     public static final Identifier CHEST_GUI_TEXTURE = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer.png");
     public static final Identifier CHEST_GUI_TEXTURE = new Identifier("roughlyenoughitems", "textures/gui/recipecontainer.png");
@@ -26,7 +29,7 @@ public class TabWidget extends WidgetWithBounds {
     public int id;
     public int id;
     public String categoryName;
     public String categoryName;
     public Rectangle bounds;
     public Rectangle bounds;
-    public RecipeCategory category;
+    public RecipeCategory<?> category;
     public int u, v;
     public int u, v;
     
     
     public TabWidget(int id, Rectangle bounds) {
     public TabWidget(int id, Rectangle bounds) {
@@ -48,7 +51,7 @@ public class TabWidget extends WidgetWithBounds {
         this(id, new Rectangle(leftX + id * tabSize, bottomY - tabSize, tabSize, tabSize), u, v);
         this(id, new Rectangle(leftX + id * tabSize, bottomY - tabSize, tabSize, tabSize), u, v);
     }
     }
     
     
-    public void setRenderer(RecipeCategory category, EntryStack logo, String categoryName, boolean selected) {
+    public void setRenderer(RecipeCategory<?> category, EntryStack logo, String categoryName, boolean selected) {
         if (logo == null) {
         if (logo == null) {
             shown = false;
             shown = false;
             this.logo = null;
             this.logo = null;
@@ -91,7 +94,6 @@ public class TabWidget extends WidgetWithBounds {
         }
         }
     }
     }
     
     
-    @SuppressWarnings("deprecation")
     private void drawTooltip() {
     private void drawTooltip() {
         if (this.minecraft.options.advancedItemTooltips)
         if (this.minecraft.options.advancedItemTooltips)
             ScreenHelper.getLastOverlay().addTooltip(QueuedTooltip.create(categoryName, Formatting.DARK_GRAY.toString() + category.getIdentifier().toString(), ClientHelper.getInstance().getFormattedModFromIdentifier(category.getIdentifier())));
             ScreenHelper.getLastOverlay().addTooltip(QueuedTooltip.create(categoryName, Formatting.DARK_GRAY.toString() + category.getIdentifier().toString(), ClientHelper.getInstance().getFormattedModFromIdentifier(category.getIdentifier())));

+ 94 - 84
src/main/java/me/shedaniel/rei/gui/widget/TextFieldWidget.java

@@ -5,8 +5,6 @@
 
 
 package me.shedaniel.rei.gui.widget;
 package me.shedaniel.rei.gui.widget;
 
 
-import com.google.common.base.Predicates;
-import com.mojang.blaze3d.platform.GlStateManager;
 import com.mojang.blaze3d.systems.RenderSystem;
 import com.mojang.blaze3d.systems.RenderSystem;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.impl.PointHelper;
 import me.shedaniel.math.impl.PointHelper;
@@ -28,7 +26,7 @@ import java.util.function.Predicate;
 
 
 public class TextFieldWidget extends WidgetWithBounds implements Tickable {
 public class TextFieldWidget extends WidgetWithBounds implements Tickable {
     
     
-    public Function<String, String> stripInvaild;
+    public Function<String, String> stripInvalid;
     protected int focusedTicks;
     protected int focusedTicks;
     protected boolean editable;
     protected boolean editable;
     protected int field_2103;
     protected int field_2103;
@@ -43,7 +41,6 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
     private boolean hasBorder;
     private boolean hasBorder;
     private boolean field_2096;
     private boolean field_2096;
     private boolean focused;
     private boolean focused;
-    private boolean field_17037;
     private boolean visible;
     private boolean visible;
     private String suggestion;
     private String suggestion;
     private Consumer<String> changedListener;
     private Consumer<String> changedListener;
@@ -58,12 +55,12 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
         this.editableColor = 14737632;
         this.editableColor = 14737632;
         this.notEditableColor = 7368816;
         this.notEditableColor = 7368816;
         this.visible = true;
         this.visible = true;
-        this.textPredicate = Predicates.alwaysTrue();
+        this.textPredicate = s -> true;
         this.renderTextProvider = (string_1, integer_1) -> {
         this.renderTextProvider = (string_1, integer_1) -> {
             return string_1;
             return string_1;
         };
         };
         this.bounds = rectangle;
         this.bounds = rectangle;
-        this.stripInvaild = s -> SharedConstants.stripInvalidChars(s);
+        this.stripInvalid = SharedConstants::stripInvalidChars;
     }
     }
     
     
     public TextFieldWidget(int x, int y, int width, int height) {
     public TextFieldWidget(int x, int y, int width, int height) {
@@ -109,13 +106,13 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
             }
             }
             
             
             this.onChanged(string_1);
             this.onChanged(string_1);
-            this.method_1872();
+            this.moveCursorToEnd();
         }
         }
     }
     }
     
     
     public String getSelectedText() {
     public String getSelectedText() {
-        int int_1 = this.cursorMax < this.cursorMin ? this.cursorMax : this.cursorMin;
-        int int_2 = this.cursorMax < this.cursorMin ? this.cursorMin : this.cursorMax;
+        int int_1 = Math.min(this.cursorMax, this.cursorMin);
+        int int_2 = Math.max(this.cursorMax, this.cursorMin);
         return this.text.substring(int_1, int_2);
         return this.text.substring(int_1, int_2);
     }
     }
     
     
@@ -125,9 +122,9 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
     
     
     public void addText(String string_1) {
     public void addText(String string_1) {
         String string_2 = "";
         String string_2 = "";
-        String string_3 = stripInvaild.apply(string_1);
-        int int_1 = this.cursorMax < this.cursorMin ? this.cursorMax : this.cursorMin;
-        int int_2 = this.cursorMax < this.cursorMin ? this.cursorMin : this.cursorMax;
+        String string_3 = stripInvalid.apply(string_1);
+        int int_1 = Math.min(this.cursorMax, this.cursorMin);
+        int int_2 = Math.max(this.cursorMax, this.cursorMin);
         int int_3 = this.maxLength - this.text.length() - (int_1 - int_2);
         int int_3 = this.maxLength - this.text.length() - (int_1 - int_2);
         if (!this.text.isEmpty()) {
         if (!this.text.isEmpty()) {
             string_2 = string_2 + this.text.substring(0, int_1);
             string_2 = string_2 + this.text.substring(0, int_1);
@@ -200,7 +197,7 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
                 if (this.textPredicate.test(string_1)) {
                 if (this.textPredicate.test(string_1)) {
                     this.text = string_1;
                     this.text = string_1;
                     if (boolean_1) {
                     if (boolean_1) {
-                        this.moveCursor(int_1);
+                        this.moveCursor(int_1, true);
                     }
                     }
                     
                     
                     this.onChanged(this.text);
                     this.onChanged(this.text);
@@ -247,32 +244,32 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
         return int_3;
         return int_3;
     }
     }
     
     
-    public void moveCursor(int int_1) {
-        this.method_1883(this.cursorMax + int_1);
+    public void moveCursor(int int_1, boolean resetSelect) {
+        this.moveCursorTo(this.cursorMax + int_1, resetSelect);
     }
     }
     
     
-    public void method_1883(int int_1) {
+    public void moveCursorTo(int int_1, boolean resetSelect) {
         this.setCursor(int_1);
         this.setCursor(int_1);
-        if (!this.field_17037) {
+        //        if (!this.field_17037) {
+        if (resetSelect) {
             this.method_1884(this.cursorMax);
             this.method_1884(this.cursorMax);
         }
         }
         
         
         this.onChanged(this.text);
         this.onChanged(this.text);
     }
     }
     
     
-    public void method_1870() {
-        this.method_1883(0);
+    public void moveCursorToHead() {
+        this.moveCursorTo(0, true);
     }
     }
     
     
-    public void method_1872() {
-        this.method_1883(this.text.length());
+    public void moveCursorToEnd() {
+        this.moveCursorTo(this.text.length(), true);
     }
     }
     
     
     public boolean keyPressed(int int_1, int int_2, int int_3) {
     public boolean keyPressed(int int_1, int int_2, int int_3) {
         if (this.isVisible() && this.isFocused()) {
         if (this.isVisible() && this.isFocused()) {
-            this.field_17037 = Screen.hasShiftDown();
             if (Screen.isSelectAll(int_1)) {
             if (Screen.isSelectAll(int_1)) {
-                this.method_1872();
+                this.moveCursorToEnd();
                 this.method_1884(0);
                 this.method_1884(0);
                 return true;
                 return true;
             } else if (Screen.isCopy(int_1)) {
             } else if (Screen.isCopy(int_1)) {
@@ -314,25 +311,25 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
                         return true;
                         return true;
                     case 262:
                     case 262:
                         if (Screen.hasControlDown()) {
                         if (Screen.hasControlDown()) {
-                            this.method_1883(this.method_1853(1));
+                            this.moveCursorTo(this.method_1853(1), !Screen.hasShiftDown());
                         } else {
                         } else {
-                            this.moveCursor(1);
+                            this.moveCursor(1, !Screen.hasShiftDown());
                         }
                         }
                         
                         
                         return true;
                         return true;
                     case 263:
                     case 263:
                         if (Screen.hasControlDown()) {
                         if (Screen.hasControlDown()) {
-                            this.method_1883(this.method_1853(-1));
+                            this.moveCursorTo(this.method_1853(-1), !Screen.hasShiftDown());
                         } else {
                         } else {
-                            this.moveCursor(-1);
+                            this.moveCursor(-1, !Screen.hasShiftDown());
                         }
                         }
                         
                         
                         return true;
                         return true;
                     case 268:
                     case 268:
-                        this.method_1870();
+                        this.moveCursorToHead();
                         return true;
                         return true;
                     case 269:
                     case 269:
-                        this.method_1872();
+                        this.moveCursorToEnd();
                         return true;
                         return true;
                 }
                 }
             }
             }
@@ -379,7 +376,7 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
                 }
                 }
                 
                 
                 String string_1 = this.font.trimToWidth(this.text.substring(this.field_2103), this.getWidth());
                 String string_1 = this.font.trimToWidth(this.text.substring(this.field_2103), this.getWidth());
-                this.method_1883(this.font.trimToWidth(string_1, int_2).length() + this.field_2103);
+                this.moveCursorTo(this.font.trimToWidth(string_1, int_2).length() + this.field_2103, true);
                 return true;
                 return true;
             } else {
             } else {
                 return false;
                 return false;
@@ -397,7 +394,7 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
         }
         }
     }
     }
     
     
-    public void render(int int_1, int int_2, float float_1) {
+    public void render(int mouseX, int mouseY, float delta) {
         if (this.isVisible()) {
         if (this.isVisible()) {
             renderBorder();
             renderBorder();
             
             
@@ -407,55 +404,50 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
             String string_1 = this.font.trimToWidth(this.text.substring(this.field_2103), this.getWidth());
             String string_1 = this.font.trimToWidth(this.text.substring(this.field_2103), this.getWidth());
             boolean boolean_1 = int_4 >= 0 && int_4 <= string_1.length();
             boolean boolean_1 = int_4 >= 0 && int_4 <= string_1.length();
             boolean boolean_2 = this.focused && this.focusedTicks / 6 % 2 == 0 && boolean_1;
             boolean boolean_2 = this.focused && this.focusedTicks / 6 % 2 == 0 && boolean_1;
-            int int_6 = this.hasBorder ? this.bounds.x + 4 : this.bounds.x;
-            int int_7 = this.hasBorder ? this.bounds.y + (this.bounds.height - 8) / 2 : this.bounds.y;
-            int int_8 = int_6;
+            int x = this.hasBorder ? this.bounds.x + 4 : this.bounds.x;
+            int y = this.hasBorder ? this.bounds.y + (this.bounds.height - 8) / 2 : this.bounds.y;
+            int int_8 = x;
             if (int_5 > string_1.length()) {
             if (int_5 > string_1.length()) {
                 int_5 = string_1.length();
                 int_5 = string_1.length();
             }
             }
             
             
             if (!string_1.isEmpty()) {
             if (!string_1.isEmpty()) {
                 String string_2 = boolean_1 ? string_1.substring(0, int_4) : string_1;
                 String string_2 = boolean_1 ? string_1.substring(0, int_4) : string_1;
-                int_8 = this.font.drawWithShadow(this.renderTextProvider.apply(string_2, this.field_2103), (float) int_6, (float) int_7, color);
+                int_8 = this.font.drawWithShadow(this.renderTextProvider.apply(string_2, this.field_2103), (float) x, (float) y, color);
             }
             }
             
             
-            boolean boolean_3 = this.cursorMax < this.text.length() || this.text.length() >= this.getMaxLength();
+            boolean isCursorInsideText = this.cursorMax < this.text.length() || this.text.length() >= this.getMaxLength();
             int int_9 = int_8;
             int int_9 = int_8;
             if (!boolean_1) {
             if (!boolean_1) {
-                int_9 = int_4 > 0 ? int_6 + this.bounds.width : int_6;
-            } else if (boolean_3) {
-                int_9 = int_8 - 1;
+                int_9 = int_4 > 0 ? x + this.bounds.width : x;
+            } else if (isCursorInsideText) {
                 --int_8;
                 --int_8;
             }
             }
+            int_9--;
             
             
             if (!string_1.isEmpty() && boolean_1 && int_4 < string_1.length()) {
             if (!string_1.isEmpty() && boolean_1 && int_4 < string_1.length()) {
-                this.font.drawWithShadow(this.renderTextProvider.apply(string_1.substring(int_4), this.cursorMax), (float) int_8, (float) int_7, color);
+                this.font.drawWithShadow(this.renderTextProvider.apply(string_1.substring(int_4), this.cursorMax), (float) int_8, (float) y, color);
             }
             }
             
             
-            if (!boolean_3 && text.isEmpty() && this.suggestion != null) {
-                renderSuggestion(int_6, int_7);
+            if (!isCursorInsideText && text.isEmpty() && this.suggestion != null) {
+                renderSuggestion(x, y);
             }
             }
             
             
-            int var10002;
-            int var10003;
             if (boolean_2) {
             if (boolean_2) {
-                if (boolean_3) {
-                    int var10001 = int_7 - 1;
-                    var10002 = int_9 + 1;
-                    var10003 = int_7 + 1;
-                    this.font.getClass();
-                    fill(int_9, var10001, var10002, var10003 + 9, -3092272);
-                } else {
-                    this.font.drawWithShadow("_", (float) int_9, (float) int_7, color);
-                }
+                //                if (isCursorInsideText) {
+                fill(int_9 + 1, y, int_9 + 2, y + 9, ((0xFF) << 24) | ((((color >> 16 & 255) / 4) & 0xFF) << 16) | ((((color >> 8 & 255) / 4) & 0xFF) << 8) | ((((color & 255) / 4) & 0xFF)));
+                //                fill(int_9, y, int_9 + 1, y + 9, 0xff343434);
+                fill(int_9, y - 1, int_9 + 1, y + 8, ((0xFF) << 24) | color);
+                //                fill(int_9 - 1, y - 1, int_9, y + 8, 0xffd0d0d0);
+                //                } else {
+                //                                    this.font.drawWithShadow("|", (float) int_9 - 2, (float) y, 0xffd0d0d0);
+                //                }
             }
             }
             
             
+            // Render selection overlay
             if (int_5 != int_4) {
             if (int_5 != int_4) {
-                int int_10 = int_6 + this.font.getStringWidth(string_1.substring(0, int_5));
-                var10002 = int_7 - 1;
-                var10003 = int_10 - 1;
-                int var10004 = int_7 + 1;
-                this.method_1886(int_9, var10002, var10003, var10004 + 9);
+                int int_10 = x + this.font.getStringWidth(string_1.substring(0, int_5));
+                this.method_1886(int_9, y - 1, int_10 - 1, y + 9, color);
             }
             }
         }
         }
     }
     }
@@ -464,41 +456,59 @@ public class TextFieldWidget extends WidgetWithBounds implements Tickable {
         this.font.drawWithShadow(this.font.trimToWidth(this.suggestion, this.getWidth()), x, y, -8355712);
         this.font.drawWithShadow(this.font.trimToWidth(this.suggestion, this.getWidth()), x, y, -8355712);
     }
     }
     
     
-    protected void method_1886(int int_1, int int_2, int int_3, int int_4) {
-        int int_6;
-        if (int_1 < int_3) {
-            int_6 = int_1;
-            int_1 = int_3;
-            int_3 = int_6;
+    protected void method_1886(int x1, int y1, int x2, int y2, int color) {
+        int tmp;
+        if (x1 < x2) {
+            tmp = x1;
+            x1 = x2;
+            x2 = tmp;
         }
         }
         
         
-        if (int_2 < int_4) {
-            int_6 = int_2;
-            int_2 = int_4;
-            int_4 = int_6;
+        if (y1 < y2) {
+            tmp = y1;
+            y1 = y2;
+            y2 = tmp;
         }
         }
         
         
-        if (int_3 > this.bounds.x + this.bounds.width) {
-            int_3 = this.bounds.x + this.bounds.width;
+        if (x2 > this.bounds.x + this.bounds.width) {
+            x2 = this.bounds.x + this.bounds.width;
         }
         }
         
         
-        if (int_1 > this.bounds.x + this.bounds.width) {
-            int_1 = this.bounds.x + this.bounds.width;
+        if (x1 > this.bounds.x + this.bounds.width) {
+            x1 = this.bounds.x + this.bounds.width;
         }
         }
         
         
-        Tessellator tessellator_1 = Tessellator.getInstance();
-        BufferBuilder bufferBuilder_1 = tessellator_1.getBuffer();
-        RenderSystem.color4f(0.0F, 0.0F, 255.0F, 255.0F);
+        int r = (color >> 16 & 255);
+        int g = (color >> 8 & 255);
+        int b = (color & 255);
+        Tessellator tessellator = Tessellator.getInstance();
+        BufferBuilder buffer = tessellator.getBuffer();
+        //        RenderSystem.color4f(0.0F, 0.0F, 255.0F, 255.0F);
+        //        RenderSystem.disableTexture();
+        //        RenderSystem.enableColorLogicOp();
+        //        RenderSystem.logicOp(GlStateManager.LogicOp.OR_REVERSE);
+        //        buffer.begin(7, VertexFormats.POSITION);
+        //        buffer.vertex(x1, y2, getBlitOffset() + 50d).next();
+        //        buffer.vertex(x2, y2, getBlitOffset() + 50d).next();
+        //        buffer.vertex(x2, y1, getBlitOffset() + 50d).next();
+        //        buffer.vertex(x1, y1, getBlitOffset() + 50d).next();
+        //        tessellator.draw();
+        //        RenderSystem.disableColorLogicOp();
+        //        RenderSystem.enableTexture();
         RenderSystem.disableTexture();
         RenderSystem.disableTexture();
-        RenderSystem.enableColorLogicOp();
-        RenderSystem.logicOp(GlStateManager.LogicOp.OR_REVERSE);
-        bufferBuilder_1.begin(7, VertexFormats.POSITION);
-        bufferBuilder_1.vertex(int_1, int_4, getBlitOffset() + 50d).next();
-        bufferBuilder_1.vertex(int_3, int_4, getBlitOffset() + 50d).next();
-        bufferBuilder_1.vertex(int_3, int_2, getBlitOffset() + 50d).next();
-        bufferBuilder_1.vertex(int_1, int_2, getBlitOffset() + 50d).next();
-        tessellator_1.draw();
-        RenderSystem.disableColorLogicOp();
+        RenderSystem.enableBlend();
+        RenderSystem.disableAlphaTest();
+        RenderSystem.blendFuncSeparate(770, 771, 1, 0);
+        RenderSystem.shadeModel(7425);
+        buffer.begin(7, VertexFormats.POSITION_COLOR);
+        buffer.vertex(x1, y2, getBlitOffset() + 50d).color(r, g, b, 120).next();
+        buffer.vertex(x2, y2, getBlitOffset() + 50d).color(r, g, b, 120).next();
+        buffer.vertex(x2, y1, getBlitOffset() + 50d).color(r, g, b, 120).next();
+        buffer.vertex(x1, y1, getBlitOffset() + 50d).color(r, g, b, 120).next();
+        tessellator.draw();
+        RenderSystem.shadeModel(7424);
+        RenderSystem.disableBlend();
+        RenderSystem.enableAlphaTest();
         RenderSystem.enableTexture();
         RenderSystem.enableTexture();
     }
     }
     
     

+ 18 - 0
src/main/java/me/shedaniel/rei/gui/widget/Widget.java

@@ -5,6 +5,7 @@
 
 
 package me.shedaniel.rei.gui.widget;
 package me.shedaniel.rei.gui.widget;
 
 
+import me.shedaniel.math.api.Point;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.font.TextRenderer;
 import net.minecraft.client.font.TextRenderer;
 import net.minecraft.client.gui.AbstractParentElement;
 import net.minecraft.client.gui.AbstractParentElement;
@@ -34,4 +35,21 @@ public abstract class Widget extends AbstractParentElement implements Drawable {
         this.setBlitOffset(z);
         this.setBlitOffset(z);
     }
     }
     
     
+    public boolean containsMouse(double mouseX, double mouseY) {
+        return false;
+    }
+    
+    public final boolean containsMouse(int mouseX, int mouseY) {
+        return containsMouse((double) mouseX, (double) mouseY);
+    }
+    
+    public final boolean containsMouse(Point point) {
+        return containsMouse(point.x, point.y);
+    }
+    
+    @Override
+    public final boolean isMouseOver(double double_1, double double_2) {
+        return containsMouse(double_1, double_2);
+    }
+    
 }
 }

+ 1 - 15
src/main/java/me/shedaniel/rei/gui/widget/WidgetWithBounds.java

@@ -5,28 +5,14 @@
 
 
 package me.shedaniel.rei.gui.widget;
 package me.shedaniel.rei.gui.widget;
 
 
-import me.shedaniel.math.api.Point;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
 
 
 public abstract class WidgetWithBounds extends Widget {
 public abstract class WidgetWithBounds extends Widget {
     
     
-    abstract public Rectangle getBounds();
-    
-    public final boolean containsMouse(int mouseX, int mouseY) {
-        return containsMouse((double) mouseX, (double) mouseY);
-    }
-    
-    public final boolean containsMouse(Point point) {
-        return containsMouse(point.x, point.y);
-    }
+    public abstract Rectangle getBounds();
     
     
     public boolean containsMouse(double mouseX, double mouseY) {
     public boolean containsMouse(double mouseX, double mouseY) {
         return getBounds().contains(mouseX, mouseY);
         return getBounds().contains(mouseX, mouseY);
     }
     }
     
     
-    @Override
-    public final boolean isMouseOver(double double_1, double double_2) {
-        return containsMouse(double_1, double_2);
-    }
-    
 }
 }

+ 51 - 10
src/main/java/me/shedaniel/rei/impl/ConfigManagerImpl.java

@@ -9,6 +9,7 @@ import com.google.common.collect.ImmutableList;
 import com.google.gson.Gson;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 import com.google.gson.GsonBuilder;
 import com.google.gson.JsonElement;
 import com.google.gson.JsonElement;
+import io.github.prospector.modmenu.ModMenu;
 import me.sargunvohra.mcmods.autoconfig1u.AutoConfig;
 import me.sargunvohra.mcmods.autoconfig1u.AutoConfig;
 import me.sargunvohra.mcmods.autoconfig1u.gui.ConfigScreenProvider;
 import me.sargunvohra.mcmods.autoconfig1u.gui.ConfigScreenProvider;
 import me.sargunvohra.mcmods.autoconfig1u.gui.registry.GuiRegistry;
 import me.sargunvohra.mcmods.autoconfig1u.gui.registry.GuiRegistry;
@@ -23,7 +24,6 @@ import me.shedaniel.clothconfig2.api.Modifier;
 import me.shedaniel.clothconfig2.api.ModifierKeyCode;
 import me.shedaniel.clothconfig2.api.ModifierKeyCode;
 import me.shedaniel.clothconfig2.gui.entries.KeyCodeEntry;
 import me.shedaniel.clothconfig2.gui.entries.KeyCodeEntry;
 import me.shedaniel.clothconfig2.gui.entries.TooltipListEntry;
 import me.shedaniel.clothconfig2.gui.entries.TooltipListEntry;
-import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
 import me.shedaniel.rei.RoughlyEnoughItemsCore;
 import me.shedaniel.rei.api.ConfigManager;
 import me.shedaniel.rei.api.ConfigManager;
 import me.shedaniel.rei.api.ConfigObject;
 import me.shedaniel.rei.api.ConfigObject;
@@ -35,11 +35,12 @@ import me.shedaniel.rei.gui.ContainerScreenOverlay;
 import me.shedaniel.rei.gui.PreRecipeViewingScreen;
 import me.shedaniel.rei.gui.PreRecipeViewingScreen;
 import me.shedaniel.rei.gui.config.RecipeScreenType;
 import me.shedaniel.rei.gui.config.RecipeScreenType;
 import me.shedaniel.rei.gui.credits.CreditsScreen;
 import me.shedaniel.rei.gui.credits.CreditsScreen;
-import me.shedaniel.rei.gui.widget.ButtonWidget;
 import me.shedaniel.rei.gui.widget.ReloadConfigButtonWidget;
 import me.shedaniel.rei.gui.widget.ReloadConfigButtonWidget;
+import net.fabricmc.loader.api.FabricLoader;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.gui.Element;
 import net.minecraft.client.gui.Element;
 import net.minecraft.client.gui.screen.Screen;
 import net.minecraft.client.gui.screen.Screen;
+import net.minecraft.client.gui.widget.AbstractButtonWidget;
 import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
 import net.minecraft.client.gui.widget.AbstractPressableButtonWidget;
 import net.minecraft.client.resource.language.I18n;
 import net.minecraft.client.resource.language.I18n;
 import net.minecraft.client.util.InputUtil;
 import net.minecraft.client.util.InputUtil;
@@ -117,9 +118,9 @@ public class ConfigManagerImpl implements ConfigManager {
             int width = 220;
             int width = 220;
             return Collections.singletonList(new TooltipListEntry<RecipeScreenType>(i13n, null) {
             return Collections.singletonList(new TooltipListEntry<RecipeScreenType>(i13n, null) {
                 private RecipeScreenType type = getUnsafely(field, config, RecipeScreenType.UNSET);
                 private RecipeScreenType type = getUnsafely(field, config, RecipeScreenType.UNSET);
-                private ButtonWidget buttonWidget = new ButtonWidget(new Rectangle(0, 0, 0, 20), "") {
+                private AbstractButtonWidget buttonWidget = new AbstractPressableButtonWidget(0, 0, 0, 20, "") {
                     @Override
                     @Override
-                    public void onPressed() {
+                    public void onPress() {
                         MinecraftClient.getInstance().openScreen(new PreRecipeViewingScreen(getScreen(), type, false, original -> {
                         MinecraftClient.getInstance().openScreen(new PreRecipeViewingScreen(getScreen(), type, false, original -> {
                             MinecraftClient.getInstance().openScreen(getScreen());
                             MinecraftClient.getInstance().openScreen(getScreen());
                             type = original ? RecipeScreenType.ORIGINAL : RecipeScreenType.VILLAGER;
                             type = original ? RecipeScreenType.ORIGINAL : RecipeScreenType.VILLAGER;
@@ -129,11 +130,11 @@ public class ConfigManagerImpl implements ConfigManager {
                     
                     
                     @Override
                     @Override
                     public void render(int mouseX, int mouseY, float delta) {
                     public void render(int mouseX, int mouseY, float delta) {
-                        setText(I18n.translate("config.roughlyenoughitems.recipeScreenType.config", type.toString()));
+                        setMessage(I18n.translate("config.roughlyenoughitems.recipeScreenType.config", type.toString()));
                         super.render(mouseX, mouseY, delta);
                         super.render(mouseX, mouseY, delta);
                     }
                     }
                 };
                 };
-                private List<ButtonWidget> children = ImmutableList.of(buttonWidget);
+                private List<Element> children = ImmutableList.of(buttonWidget);
                 
                 
                 @Override
                 @Override
                 public RecipeScreenType getValue() {
                 public RecipeScreenType getValue() {
@@ -159,10 +160,10 @@ public class ConfigManagerImpl implements ConfigManager {
                 public void render(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
                 public void render(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
                     super.render(index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta);
                     super.render(index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta);
                     Window window = MinecraftClient.getInstance().getWindow();
                     Window window = MinecraftClient.getInstance().getWindow();
-                    this.buttonWidget.enabled = this.isEditable();
-                    this.buttonWidget.getBounds().y = y;
-                    this.buttonWidget.getBounds().x = x + entryWidth / 2 - width / 2;
-                    this.buttonWidget.getBounds().width = width;
+                    this.buttonWidget.active = this.isEditable();
+                    this.buttonWidget.y = y;
+                    this.buttonWidget.x = x + entryWidth / 2 - width / 2;
+                    this.buttonWidget.setWidth(width);
                     this.buttonWidget.render(mouseX, mouseY, delta);
                     this.buttonWidget.render(mouseX, mouseY, delta);
                 }
                 }
             });
             });
@@ -228,6 +229,46 @@ public class ConfigManagerImpl implements ConfigManager {
             provider.setOptionFunction((baseI13n, field) -> field.isAnnotationPresent(ConfigObject.DontApplyFieldName.class) ? baseI13n : String.format("%s.%s", baseI13n, field.getName()));
             provider.setOptionFunction((baseI13n, field) -> field.isAnnotationPresent(ConfigObject.DontApplyFieldName.class) ? baseI13n : String.format("%s.%s", baseI13n, field.getName()));
             provider.setCategoryFunction((baseI13n, categoryName) -> String.format("%s.%s", baseI13n, categoryName));
             provider.setCategoryFunction((baseI13n, categoryName) -> String.format("%s.%s", baseI13n, categoryName));
             provider.setBuildFunction(builder -> {
             provider.setBuildFunction(builder -> {
+                if (FabricLoader.getInstance().isModLoaded("modmenu")) {
+                    builder.getOrCreateCategory("config.roughlyenoughitems.!general").addEntry(new TooltipListEntry<Object>(I18n.translate("config.roughlyenoughitems.smooth_scrolling"), null) {
+                        int width = 220;
+                        private AbstractButtonWidget buttonWidget = new AbstractPressableButtonWidget(0, 0, 0, 20, this.getFieldName()) {
+                            public void onPress() {
+                                Screen screen = ModMenu.getConfigScreen("cloth-config2", parent);
+                                if (screen != null) {
+                                    MinecraftClient.getInstance().openScreen(screen);
+                                } else
+                                    ModMenu.openConfigScreen("cloth-config2");
+                            }
+                        };
+                        private List<Element> children = ImmutableList.of(this.buttonWidget);
+                        
+                        public Object getValue() {
+                            return null;
+                        }
+                        
+                        public Optional<Object> getDefaultValue() {
+                            return Optional.empty();
+                        }
+                        
+                        public void save() {
+                        }
+                        
+                        public List<? extends Element> children() {
+                            return this.children;
+                        }
+                        
+                        public void render(int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean isSelected, float delta) {
+                            super.render(index, y, x, entryWidth, entryHeight, mouseX, mouseY, isSelected, delta);
+                            Window window = MinecraftClient.getInstance().getWindow();
+                            this.buttonWidget.active = this.isEditable();
+                            this.buttonWidget.y = y;
+                            this.buttonWidget.x = x + entryWidth / 2 - this.width / 2;
+                            this.buttonWidget.setWidth(this.width);
+                            this.buttonWidget.render(mouseX, mouseY, delta);
+                        }
+                    });
+                }
                 return builder.setAfterInitConsumer(screen -> {
                 return builder.setAfterInitConsumer(screen -> {
                     if (MinecraftClient.getInstance().getNetworkHandler() != null && MinecraftClient.getInstance().getNetworkHandler().getRecipeManager() != null) {
                     if (MinecraftClient.getInstance().getNetworkHandler() != null && MinecraftClient.getInstance().getNetworkHandler().getRecipeManager() != null) {
                         ((ScreenHooks) screen).cloth_addButton(new ReloadConfigButtonWidget(4, 4, 100, 20, I18n.translate("text.rei.reload_config"), buttonWidget -> {
                         ((ScreenHooks) screen).cloth_addButton(new ReloadConfigButtonWidget(4, 4, 100, 20, I18n.translate("text.rei.reload_config"), buttonWidget -> {

+ 2 - 2
src/main/java/me/shedaniel/rei/impl/ConfigObjectImpl.java

@@ -200,7 +200,7 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
     
     
     @Override
     @Override
     public boolean doesFastEntryRendering() {
     public boolean doesFastEntryRendering() {
-        return performance.fastEntryRendering;
+        return performance.newFastEntryRendering;
     }
     }
     
     
     @Override
     @Override
@@ -326,6 +326,6 @@ public class ConfigObjectImpl implements ConfigObject, ConfigData {
     
     
     public static class Performance {
     public static class Performance {
         @Comment("Whether REI should render entry's enchantment glint") private boolean renderEntryEnchantmentGlint = true;
         @Comment("Whether REI should render entry's enchantment glint") private boolean renderEntryEnchantmentGlint = true;
-        @ConfigEntry.Gui.Excluded private boolean fastEntryRendering = false;
+        private boolean newFastEntryRendering = true;
     }
     }
 }
 }

+ 59 - 41
src/main/java/me/shedaniel/rei/impl/ItemEntryStack.java

@@ -8,10 +8,7 @@ package me.shedaniel.rei.impl;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Lists;
 import com.mojang.blaze3d.platform.GlStateManager;
 import com.mojang.blaze3d.platform.GlStateManager;
 import me.shedaniel.math.api.Rectangle;
 import me.shedaniel.math.api.Rectangle;
-import me.shedaniel.rei.api.ClientHelper;
-import me.shedaniel.rei.api.ConfigObject;
-import me.shedaniel.rei.api.EntryStack;
-import me.shedaniel.rei.api.ItemStackHook;
+import me.shedaniel.rei.api.*;
 import me.shedaniel.rei.gui.widget.QueuedTooltip;
 import me.shedaniel.rei.gui.widget.QueuedTooltip;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.MinecraftClient;
 import net.minecraft.client.render.OverlayTexture;
 import net.minecraft.client.render.OverlayTexture;
@@ -31,7 +28,7 @@ import java.util.Map;
 import java.util.Optional;
 import java.util.Optional;
 
 
 @Deprecated
 @Deprecated
-public class ItemEntryStack extends AbstractEntryStack {
+public class ItemEntryStack extends AbstractEntryStack implements OptimalEntryStack {
     
     
     private ItemStack itemStack;
     private ItemStack itemStack;
     private int hash = -1;
     private int hash = -1;
@@ -152,46 +149,67 @@ public class ItemEntryStack extends AbstractEntryStack {
         return QueuedTooltip.create(toolTip);
         return QueuedTooltip.create(toolTip);
     }
     }
     
     
-    @SuppressWarnings("PointlessBooleanExpression")
+    private static final MatrixStack matrices = new MatrixStack();
+    private final ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
+    
     @Override
     @Override
     public void render(Rectangle bounds, int mouseX, int mouseY, float delta) {
     public void render(Rectangle bounds, int mouseX, int mouseY, float delta) {
+        optimisedRenderStart(delta);
+        optimisedRenderBase(bounds, mouseX, mouseY, delta);
+        optimisedRenderOverlay(bounds, mouseX, mouseY, delta);
+        optimisedRenderEnd(delta);
+    }
+    
+    @Override
+    public void optimisedRenderStart(float delta) {
+        MinecraftClient.getInstance().getTextureManager().bindTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEX);
+        GlStateManager.enableRescaleNormal();
+    }
+    
+    @Override
+    public void optimisedRenderEnd(float delta) {
+        GlStateManager.disableRescaleNormal();
+    }
+    
+    private BakedModel getModelFromStack(ItemStack stack) {
+        BakedModel model = itemRenderer.getModels().getModel(stack);
+        if (stack.getItem().hasPropertyGetters())
+            model = model.getItemPropertyOverrides().apply(model, stack, null, null);
+        if (model != null)
+            return model;
+        return itemRenderer.getModels().getModelManager().getMissingModel();
+    }
+    
+    @Override
+    public void optimisedRenderBase(Rectangle bounds, int mouseX, int mouseY, float delta) {
         if (!isEmpty() && get(Settings.RENDER).get()) {
         if (!isEmpty() && get(Settings.RENDER).get()) {
             ItemStack stack = getItemStack();
             ItemStack stack = getItemStack();
-            if (ConfigObject.getInstance().doesFastEntryRendering() || true) {
-                ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
-                itemRenderer.zOffset = getZ();
-                BakedModel model = itemRenderer.getModels().getModel(stack);
-                if (stack.getItem().hasPropertyGetters())
-                    model = model.getItemPropertyOverrides().apply(model, stack, null, null);
-                if (model == null)
-                    model = itemRenderer.getModels().getModelManager().getMissingModel();
-                MinecraftClient.getInstance().getTextureManager().bindTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEX);
-                GlStateManager.enableRescaleNormal();
-                MatrixStack matrices = new MatrixStack();
-                matrices.translate(bounds.getCenterX(), bounds.getCenterY(), 100.0F + getZ());
-                matrices.scale(bounds.getWidth(), (bounds.getWidth() + bounds.getHeight()) / -2f, bounds.getHeight());
-                VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
-                boolean bl = !model.hasDepthInGui();
-                if (bl)
-                    GlStateManager.method_24221();
-                itemRenderer.renderItem(stack, ModelTransformation.Type.GUI, false, matrices, immediate, 15728880, OverlayTexture.DEFAULT_UV, model);
-                immediate.draw();
-                if (bl)
-                    GlStateManager.method_24222();
-                GlStateManager.disableRescaleNormal();
-                itemRenderer.renderGuiItemOverlay(MinecraftClient.getInstance().textRenderer, stack, bounds.x, bounds.y, get(Settings.RENDER_COUNTS).get() ? get(Settings.COUNTS).apply(this) : "");
-                itemRenderer.zOffset = 0.0F;
-            } else {
-                ((ItemStackHook) (Object) stack).rei_setRenderEnchantmentGlint(get(Settings.Item.RENDER_ENCHANTMENT_GLINT).get());
-                ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer();
-                itemRenderer.zOffset = getZ();
-                int i1 = bounds.x;
-                int i2 = bounds.y;
-                itemRenderer.renderGuiItemIcon(stack, i1, i2);
-                itemRenderer.renderGuiItemOverlay(MinecraftClient.getInstance().textRenderer, stack, i1, i2, get(Settings.RENDER_COUNTS).get() ? get(Settings.COUNTS).apply(this) : "");
-                itemRenderer.zOffset = 0.0F;
-                ((ItemStackHook) (Object) stack).rei_setRenderEnchantmentGlint(true);
-            }
+            ((ItemStackHook) (Object) stack).rei_setRenderEnchantmentGlint(get(Settings.Item.RENDER_ENCHANTMENT_GLINT).get());
+            itemRenderer.zOffset = getZ();
+            matrices.push();
+            matrices.translate(bounds.getCenterX(), bounds.getCenterY(), 100.0F + getZ());
+            matrices.scale(bounds.getWidth(), (bounds.getWidth() + bounds.getHeight()) / -2f, bounds.getHeight());
+            VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers();
+            BakedModel model = getModelFromStack(stack);
+            boolean bl = !model.hasDepthInGui();
+            if (bl)
+                GlStateManager.method_24221();
+            itemRenderer.renderItem(stack, ModelTransformation.Type.GUI, false, matrices, immediate, 15728880, OverlayTexture.DEFAULT_UV, model);
+            immediate.draw();
+            if (bl)
+                GlStateManager.method_24222();
+            itemRenderer.zOffset = 0.0F;
+            matrices.pop();
+            ((ItemStackHook) (Object) stack).rei_setRenderEnchantmentGlint(false);
+        }
+    }
+    
+    @Override
+    public void optimisedRenderOverlay(Rectangle bounds, int mouseX, int mouseY, float delta) {
+        if (!isEmpty() && get(Settings.RENDER).get()) {
+            itemRenderer.zOffset = getZ();
+            itemRenderer.renderGuiItemOverlay(MinecraftClient.getInstance().textRenderer, getItemStack(), bounds.x, bounds.y, get(Settings.RENDER_COUNTS).get() ? get(Settings.COUNTS).apply(this) : "");
+            itemRenderer.zOffset = 0.0F;
         }
         }
     }
     }
 }
 }

+ 2 - 1
src/main/java/me/shedaniel/rei/impl/ScreenHelper.java

@@ -11,6 +11,7 @@ import com.google.common.collect.Sets;
 import me.shedaniel.cloth.hooks.ClothClientHooks;
 import me.shedaniel.cloth.hooks.ClothClientHooks;
 import me.shedaniel.rei.api.ConfigManager;
 import me.shedaniel.rei.api.ConfigManager;
 import me.shedaniel.rei.api.ConfigObject;
 import me.shedaniel.rei.api.ConfigObject;
+import me.shedaniel.rei.api.annotations.Internal;
 import me.shedaniel.rei.gui.ContainerScreenOverlay;
 import me.shedaniel.rei.gui.ContainerScreenOverlay;
 import me.shedaniel.rei.gui.OverlaySearchField;
 import me.shedaniel.rei.gui.OverlaySearchField;
 import me.shedaniel.rei.listeners.ContainerScreenHooks;
 import me.shedaniel.rei.listeners.ContainerScreenHooks;
@@ -34,7 +35,7 @@ public class ScreenHelper implements ClientModInitializer {
      * @deprecated Use getters instead
      * @deprecated Use getters instead
      */
      */
     @Deprecated public static OverlaySearchField searchField;
     @Deprecated public static OverlaySearchField searchField;
-    public static List<ItemStack> inventoryStacks = Lists.newArrayList();
+    @Deprecated @Internal public static List<ItemStack> inventoryStacks = Lists.newArrayList();
     private static ContainerScreenOverlay overlay;
     private static ContainerScreenOverlay overlay;
     private static AbstractContainerScreen<?> lastContainerScreen = null;
     private static AbstractContainerScreen<?> lastContainerScreen = null;
     private static LinkedHashSet<Screen> lastRecipeScreen = Sets.newLinkedHashSetWithExpectedSize(5);
     private static LinkedHashSet<Screen> lastRecipeScreen = Sets.newLinkedHashSetWithExpectedSize(5);

+ 10 - 11
src/main/java/me/shedaniel/rei/impl/Weather.java

@@ -5,6 +5,9 @@
 
 
 package me.shedaniel.rei.impl;
 package me.shedaniel.rei.impl;
 
 
+import me.shedaniel.rei.api.annotations.Internal;
+
+@Internal
 public enum Weather {
 public enum Weather {
     CLEAR(0, "text.rei.weather.clear"),
     CLEAR(0, "text.rei.weather.clear"),
     RAIN(1, "text.rei.weather.rain"),
     RAIN(1, "text.rei.weather.rain"),
@@ -18,20 +21,16 @@ public enum Weather {
         this.translateKey = translateKey;
         this.translateKey = translateKey;
     }
     }
     
     
-    public static Weather byId(int int_1) {
-        return byId(int_1, CLEAR);
+    public static Weather byId(int id) {
+        return byId(id, CLEAR);
     }
     }
     
     
-    public static Weather byId(int int_1, Weather gameMode_1) {
-        Weather[] var2 = values();
-        int var3 = var2.length;
-        
-        for (int var4 = 0; var4 < var3; ++var4) {
-            Weather gameMode_2 = var2[var4];
-            if (gameMode_2.id == int_1)
-                return gameMode_2;
+    public static Weather byId(int id, Weather defaultWeather) {
+        for (Weather weather : values()) {
+            if (weather.id == id)
+                return weather;
         }
         }
-        return gameMode_1;
+        return defaultWeather;
     }
     }
     
     
     public int getId() {
     public int getId() {

+ 6 - 6
src/main/java/me/shedaniel/rei/listeners/ContainerScreenHooks.java

@@ -12,20 +12,20 @@ import org.spongepowered.asm.mixin.gen.Accessor;
 
 
 @Mixin(AbstractContainerScreen.class)
 @Mixin(AbstractContainerScreen.class)
 public interface ContainerScreenHooks {
 public interface ContainerScreenHooks {
-
+    
     @Accessor("x")
     @Accessor("x")
     int rei_getContainerLeft();
     int rei_getContainerLeft();
-
+    
     @Accessor("y")
     @Accessor("y")
     int rei_getContainerTop();
     int rei_getContainerTop();
-
+    
     @Accessor("containerWidth")
     @Accessor("containerWidth")
     int rei_getContainerWidth();
     int rei_getContainerWidth();
-
+    
     @Accessor("containerHeight")
     @Accessor("containerHeight")
     int rei_getContainerHeight();
     int rei_getContainerHeight();
-
+    
     @Accessor("focusedSlot")
     @Accessor("focusedSlot")
     Slot rei_getHoveredSlot();
     Slot rei_getHoveredSlot();
-
+    
 }
 }

+ 6 - 6
src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultCategoryHandler.java

@@ -29,11 +29,11 @@ import net.minecraft.util.PacketByteBuf;
 import java.util.List;
 import java.util.List;
 
 
 public class DefaultCategoryHandler implements AutoTransferHandler {
 public class DefaultCategoryHandler implements AutoTransferHandler {
-
+    
     public static boolean canUseMovePackets() {
     public static boolean canUseMovePackets() {
         return ClientSidePacketRegistry.INSTANCE.canServerReceive(RoughlyEnoughItemsNetwork.MOVE_ITEMS_PACKET);
         return ClientSidePacketRegistry.INSTANCE.canServerReceive(RoughlyEnoughItemsNetwork.MOVE_ITEMS_PACKET);
     }
     }
-
+    
     @Override
     @Override
     public Result handle(Context context) {
     public Result handle(Context context) {
         if (!(context.getRecipe() instanceof TransferRecipeDisplay))
         if (!(context.getRecipe() instanceof TransferRecipeDisplay))
@@ -54,14 +54,14 @@ public class DefaultCategoryHandler implements AutoTransferHandler {
             return Result.createFailed("error.rei.not.on.server");
             return Result.createFailed("error.rei.not.on.server");
         if (!context.isActuallyCrafting())
         if (!context.isActuallyCrafting())
             return Result.createSuccessful();
             return Result.createSuccessful();
-
+        
         context.getMinecraft().openScreen(containerScreen);
         context.getMinecraft().openScreen(containerScreen);
         if (containerScreen instanceof RecipeBookProvider)
         if (containerScreen instanceof RecipeBookProvider)
             ((RecipeBookGuiHooks) ((RecipeBookProvider) containerScreen).getRecipeBookGui()).rei_getGhostSlots().reset();
             ((RecipeBookGuiHooks) ((RecipeBookProvider) containerScreen).getRecipeBookGui()).rei_getGhostSlots().reset();
         PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
         PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer());
         buf.writeIdentifier(recipe.getRecipeCategory());
         buf.writeIdentifier(recipe.getRecipeCategory());
         buf.writeBoolean(Screen.hasShiftDown());
         buf.writeBoolean(Screen.hasShiftDown());
-
+        
         buf.writeInt(input.size());
         buf.writeInt(input.size());
         for (List<EntryStack> stacks : input) {
         for (List<EntryStack> stacks : input) {
             buf.writeInt(stacks.size());
             buf.writeInt(stacks.size());
@@ -75,12 +75,12 @@ public class DefaultCategoryHandler implements AutoTransferHandler {
         ClientSidePacketRegistry.INSTANCE.sendToServer(RoughlyEnoughItemsNetwork.MOVE_ITEMS_PACKET, buf);
         ClientSidePacketRegistry.INSTANCE.sendToServer(RoughlyEnoughItemsNetwork.MOVE_ITEMS_PACKET, buf);
         return Result.createSuccessful();
         return Result.createSuccessful();
     }
     }
-
+    
     @Override
     @Override
     public double getPriority() {
     public double getPriority() {
         return -10;
         return -10;
     }
     }
-
+    
     public IntList hasItems(List<List<EntryStack>> inputs) {
     public IntList hasItems(List<List<EntryStack>> inputs) {
         // Create a clone of player's inventory, and count
         // Create a clone of player's inventory, and count
         DefaultedList<ItemStack> copyMain = DefaultedList.of();
         DefaultedList<ItemStack> copyMain = DefaultedList.of();

+ 1 - 1
src/main/java/me/shedaniel/rei/plugin/autocrafting/DefaultRecipeBookHandler.java

@@ -73,7 +73,7 @@ public class DefaultRecipeBookHandler implements AutoTransferHandler {
         }
         }
         return Result.createNotApplicable();
         return Result.createNotApplicable();
     }
     }
-
+    
     @Override
     @Override
     public double getPriority() {
     public double getPriority() {
         return -20;
         return -20;

+ 3 - 3
src/main/java/me/shedaniel/rei/plugin/brewing/BrewingRecipe.java

@@ -9,15 +9,15 @@ import net.minecraft.item.Item;
 import net.minecraft.recipe.Ingredient;
 import net.minecraft.recipe.Ingredient;
 
 
 public class BrewingRecipe {
 public class BrewingRecipe {
-
+    
     public final Item input;
     public final Item input;
     public final Ingredient ingredient;
     public final Ingredient ingredient;
     public final Item output;
     public final Item output;
-
+    
     public BrewingRecipe(Item object_1, Ingredient ingredient_1, Item object_2) {
     public BrewingRecipe(Item object_1, Ingredient ingredient_1, Item object_2) {
         this.input = object_1;
         this.input = object_1;
         this.ingredient = ingredient_1;
         this.ingredient = ingredient_1;
         this.output = object_2;
         this.output = object_2;
     }
     }
-
+    
 }
 }

+ 5 - 5
src/main/java/me/shedaniel/rei/plugin/campfire/DefaultCampfireCategory.java

@@ -27,22 +27,22 @@ import java.util.List;
 import java.util.function.Supplier;
 import java.util.function.Supplier;
 
 
 public class DefaultCampfireCategory implements RecipeCategory<DefaultCampfireDisplay> {
 public class DefaultCampfireCategory implements RecipeCategory<DefaultCampfireDisplay> {
-
+    
     @Override
     @Override
     public Identifier getIdentifier() {
     public Identifier getIdentifier() {
         return DefaultPlugin.CAMPFIRE;
         return DefaultPlugin.CAMPFIRE;
     }
     }
-
+    
     @Override
     @Override
     public EntryStack getLogo() {
     public EntryStack getLogo() {
         return EntryStack.create(Blocks.CAMPFIRE);
         return EntryStack.create(Blocks.CAMPFIRE);
     }
     }
-
+    
     @Override
     @Override
     public String getCategoryName() {
     public String getCategoryName() {
         return I18n.translate("category.rei.campfire");
         return I18n.translate("category.rei.campfire");
     }
     }
-
+    
     @Override
     @Override
     public List<Widget> setupDisplay(Supplier<DefaultCampfireDisplay> recipeDisplaySupplier, Rectangle bounds) {
     public List<Widget> setupDisplay(Supplier<DefaultCampfireDisplay> recipeDisplaySupplier, Rectangle bounds) {
         Point startPoint = new Point(bounds.getCenterX() - 41, bounds.y + 10);
         Point startPoint = new Point(bounds.getCenterX() - 41, bounds.y + 10);
@@ -59,7 +59,7 @@ public class DefaultCampfireCategory implements RecipeCategory<DefaultCampfireDi
                 MinecraftClient.getInstance().textRenderer.draw(text, bounds.x + bounds.width - length - 5, bounds.y + 5, ScreenHelper.isDarkModeEnabled() ? 0xFFBBBBBB : 0xFF404040);
                 MinecraftClient.getInstance().textRenderer.draw(text, bounds.x + bounds.width - length - 5, bounds.y + 5, ScreenHelper.isDarkModeEnabled() ? 0xFFBBBBBB : 0xFF404040);
             }
             }
         }));
         }));
-        widgets.add(new RecipeArrowWidget(startPoint.x + 24, startPoint.y + 8, true));
+        widgets.add(RecipeArrowWidget.create(new Point(startPoint.x + 24, startPoint.y + 8), true));
         widgets.add(EntryWidget.create(startPoint.x + 1, startPoint.y + 1).entries(recipeDisplaySupplier.get().getInputEntries().get(0)));
         widgets.add(EntryWidget.create(startPoint.x + 1, startPoint.y + 1).entries(recipeDisplaySupplier.get().getInputEntries().get(0)));
         widgets.add(EntryWidget.create(startPoint.x + 61, startPoint.y + 9).entries(recipeDisplaySupplier.get().getOutputEntries()).noBackground());
         widgets.add(EntryWidget.create(startPoint.x + 61, startPoint.y + 9).entries(recipeDisplaySupplier.get().getOutputEntries()).noBackground());
         return widgets;
         return widgets;

+ 10 - 10
src/main/java/me/shedaniel/rei/plugin/composting/DefaultCompostingDisplay.java

@@ -16,12 +16,12 @@ import java.util.*;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 public class DefaultCompostingDisplay implements RecipeDisplay {
 public class DefaultCompostingDisplay implements RecipeDisplay {
-
+    
     private List<EntryStack> order, allItems;
     private List<EntryStack> order, allItems;
     private Map<ItemConvertible, Float> inputMap;
     private Map<ItemConvertible, Float> inputMap;
     private List<EntryStack> output;
     private List<EntryStack> output;
     private int page;
     private int page;
-
+    
     public DefaultCompostingDisplay(int page, List<ItemConvertible> order, Map<ItemConvertible, Float> inputMap, List<ItemConvertible> allItems, ItemStack[] output) {
     public DefaultCompostingDisplay(int page, List<ItemConvertible> order, Map<ItemConvertible, Float> inputMap, List<ItemConvertible> allItems, ItemStack[] output) {
         this.page = page;
         this.page = page;
         this.order = order.stream().map(EntryStack::create).collect(Collectors.toList());
         this.order = order.stream().map(EntryStack::create).collect(Collectors.toList());
@@ -29,11 +29,11 @@ public class DefaultCompostingDisplay implements RecipeDisplay {
         this.output = Arrays.asList(output).stream().map(EntryStack::create).collect(Collectors.toList());
         this.output = Arrays.asList(output).stream().map(EntryStack::create).collect(Collectors.toList());
         this.allItems = allItems.stream().map(EntryStack::create).collect(Collectors.toList());
         this.allItems = allItems.stream().map(EntryStack::create).collect(Collectors.toList());
     }
     }
-
+    
     public int getPage() {
     public int getPage() {
         return page;
         return page;
     }
     }
-
+    
     @Override
     @Override
     public List<List<EntryStack>> getInputEntries() {
     public List<List<EntryStack>> getInputEntries() {
         List<List<EntryStack>> lists = new ArrayList<>();
         List<List<EntryStack>> lists = new ArrayList<>();
@@ -42,28 +42,28 @@ public class DefaultCompostingDisplay implements RecipeDisplay {
         }
         }
         return lists;
         return lists;
     }
     }
-
+    
     public Map<ItemConvertible, Float> getInputMap() {
     public Map<ItemConvertible, Float> getInputMap() {
         return inputMap;
         return inputMap;
     }
     }
-
+    
     @Override
     @Override
     public List<EntryStack> getOutputEntries() {
     public List<EntryStack> getOutputEntries() {
         return output;
         return output;
     }
     }
-
+    
     @Override
     @Override
     public Identifier getRecipeCategory() {
     public Identifier getRecipeCategory() {
         return DefaultPlugin.COMPOSTING;
         return DefaultPlugin.COMPOSTING;
     }
     }
-
+    
     @Override
     @Override
     public List<List<EntryStack>> getRequiredEntries() {
     public List<List<EntryStack>> getRequiredEntries() {
         return Collections.singletonList(allItems);
         return Collections.singletonList(allItems);
     }
     }
-
+    
     public List<EntryStack> getItemsByOrder() {
     public List<EntryStack> getItemsByOrder() {
         return order;
         return order;
     }
     }
-
+    
 }
 }

+ 8 - 8
src/main/java/me/shedaniel/rei/plugin/cooking/DefaultCookingCategory.java

@@ -34,13 +34,13 @@ public class DefaultCookingCategory implements TransferRecipeCategory<DefaultCoo
     private Identifier identifier;
     private Identifier identifier;
     private EntryStack logo;
     private EntryStack logo;
     private String categoryName;
     private String categoryName;
-
+    
     public DefaultCookingCategory(Identifier identifier, EntryStack logo, String categoryName) {
     public DefaultCookingCategory(Identifier identifier, EntryStack logo, String categoryName) {
         this.identifier = identifier;
         this.identifier = identifier;
         this.logo = logo;
         this.logo = logo;
         this.categoryName = categoryName;
         this.categoryName = categoryName;
     }
     }
-
+    
     @Override
     @Override
     public void renderRedSlots(List<Widget> widgets, Rectangle bounds, DefaultCookingDisplay display, IntList redSlots) {
     public void renderRedSlots(List<Widget> widgets, Rectangle bounds, DefaultCookingDisplay display, IntList redSlots) {
         Point startPoint = new Point(bounds.getCenterX() - 41, bounds.getCenterY() - 27);
         Point startPoint = new Point(bounds.getCenterX() - 41, bounds.getCenterY() - 27);
@@ -50,7 +50,7 @@ public class DefaultCookingCategory implements TransferRecipeCategory<DefaultCoo
         }
         }
         RenderSystem.translatef(0, 0, -400);
         RenderSystem.translatef(0, 0, -400);
     }
     }
-
+    
     @Override
     @Override
     public List<Widget> setupDisplay(Supplier<DefaultCookingDisplay> recipeDisplaySupplier, Rectangle bounds) {
     public List<Widget> setupDisplay(Supplier<DefaultCookingDisplay> recipeDisplaySupplier, Rectangle bounds) {
         Point startPoint = new Point(bounds.getCenterX() - 41, bounds.y + 10);
         Point startPoint = new Point(bounds.getCenterX() - 41, bounds.y + 10);
@@ -65,15 +65,15 @@ public class DefaultCookingCategory implements TransferRecipeCategory<DefaultCoo
                 String text = I18n.translate("category.rei.cooking.xp", recipeDisplaySupplier.get().getXp());
                 String text = I18n.translate("category.rei.cooking.xp", recipeDisplaySupplier.get().getXp());
                 int length = MinecraftClient.getInstance().textRenderer.getStringWidth(text);
                 int length = MinecraftClient.getInstance().textRenderer.getStringWidth(text);
                 MinecraftClient.getInstance().textRenderer.draw(text, bounds.x + bounds.width - length - 5, bounds.y + 5, ScreenHelper.isDarkModeEnabled() ? 0xFFBBBBBB : 0xFF404040);
                 MinecraftClient.getInstance().textRenderer.draw(text, bounds.x + bounds.width - length - 5, bounds.y + 5, ScreenHelper.isDarkModeEnabled() ? 0xFFBBBBBB : 0xFF404040);
-    
+                
             }
             }
         }));
         }));
-        widgets.add(new RecipeArrowWidget(startPoint.x + 24, startPoint.y + 8, true));
+        widgets.add(RecipeArrowWidget.create(new Point(startPoint.x + 24, startPoint.y + 8), true));
         widgets.add(EntryWidget.create(startPoint.x + 1, startPoint.y + 1).entries(recipeDisplaySupplier.get().getInputEntries().get(0)));
         widgets.add(EntryWidget.create(startPoint.x + 1, startPoint.y + 1).entries(recipeDisplaySupplier.get().getInputEntries().get(0)));
         widgets.add(EntryWidget.create(startPoint.x + 61, startPoint.y + 9).entries(recipeDisplaySupplier.get().getOutputEntries()).noBackground());
         widgets.add(EntryWidget.create(startPoint.x + 61, startPoint.y + 9).entries(recipeDisplaySupplier.get().getOutputEntries()).noBackground());
         return widgets;
         return widgets;
     }
     }
-
+    
     @Override
     @Override
     public RecipeEntry getSimpleRenderer(DefaultCookingDisplay recipe) {
     public RecipeEntry getSimpleRenderer(DefaultCookingDisplay recipe) {
         return SimpleRecipeEntry.create(Collections.singletonList(recipe.getInputEntries().get(0)), recipe.getOutputEntries());
         return SimpleRecipeEntry.create(Collections.singletonList(recipe.getInputEntries().get(0)), recipe.getOutputEntries());
@@ -88,12 +88,12 @@ public class DefaultCookingCategory implements TransferRecipeCategory<DefaultCoo
     public Identifier getIdentifier() {
     public Identifier getIdentifier() {
         return identifier;
         return identifier;
     }
     }
-
+    
     @Override
     @Override
     public EntryStack getLogo() {
     public EntryStack getLogo() {
         return logo;
         return logo;
     }
     }
-
+    
     @Override
     @Override
     public String getCategoryName() {
     public String getCategoryName() {
         return I18n.translate(categoryName);
         return I18n.translate(categoryName);

+ 1 - 1
src/main/java/me/shedaniel/rei/plugin/information/DefaultInformationCategory.java

@@ -99,7 +99,7 @@ public class DefaultInformationCategory implements RecipeCategory<DefaultInforma
     public List<Widget> setupDisplay(Supplier<DefaultInformationDisplay> recipeDisplaySupplier, Rectangle bounds) {
     public List<Widget> setupDisplay(Supplier<DefaultInformationDisplay> recipeDisplaySupplier, Rectangle bounds) {
         DefaultInformationDisplay display = recipeDisplaySupplier.get();
         DefaultInformationDisplay display = recipeDisplaySupplier.get();
         List<Widget> widgets = Lists.newArrayList();
         List<Widget> widgets = Lists.newArrayList();
-        widgets.add(new LabelWidget(new Point(bounds.getCenterX(), bounds.y + 3), display.getName().asFormattedString()).noShadow().color(ScreenHelper.isDarkModeEnabled() ? 0xFFBBBBBB : 0xFF404040));
+        widgets.add(LabelWidget.create(new Point(bounds.getCenterX(), bounds.y + 3), display.getName().asFormattedString()).noShadow().color(ScreenHelper.isDarkModeEnabled() ? 0xFFBBBBBB : 0xFF404040));
         widgets.add(EntryWidget.create(bounds.getCenterX() - 8, bounds.y + 15).entries(display.getEntryStacks()));
         widgets.add(EntryWidget.create(bounds.getCenterX() - 8, bounds.y + 15).entries(display.getEntryStacks()));
         Rectangle rectangle = new Rectangle(bounds.getCenterX() - (bounds.width / 2), bounds.y + 35, bounds.width, bounds.height - 40);
         Rectangle rectangle = new Rectangle(bounds.getCenterX() - (bounds.width / 2), bounds.y + 35, bounds.width, bounds.height - 40);
         widgets.add(new SlotBaseWidget(rectangle));
         widgets.add(new SlotBaseWidget(rectangle));

+ 8 - 8
src/main/java/me/shedaniel/rei/plugin/stonecutting/DefaultStoneCuttingDisplay.java

@@ -22,16 +22,16 @@ import java.util.Optional;
 import java.util.stream.Collectors;
 import java.util.stream.Collectors;
 
 
 public class DefaultStoneCuttingDisplay implements RecipeDisplay {
 public class DefaultStoneCuttingDisplay implements RecipeDisplay {
-
+    
     private List<List<EntryStack>> inputs;
     private List<List<EntryStack>> inputs;
     private List<EntryStack> output;
     private List<EntryStack> output;
     private StonecuttingRecipe display;
     private StonecuttingRecipe display;
-
+    
     public DefaultStoneCuttingDisplay(StonecuttingRecipe recipe) {
     public DefaultStoneCuttingDisplay(StonecuttingRecipe recipe) {
         this(recipe.getPreviewInputs(), recipe.getOutput());
         this(recipe.getPreviewInputs(), recipe.getOutput());
         this.display = recipe;
         this.display = recipe;
     }
     }
-
+    
     public DefaultStoneCuttingDisplay(DefaultedList<Ingredient> ingredients, ItemStack output) {
     public DefaultStoneCuttingDisplay(DefaultedList<Ingredient> ingredients, ItemStack output) {
         this.inputs = ingredients.stream().map(i -> {
         this.inputs = ingredients.stream().map(i -> {
             List<EntryStack> entries = new ArrayList<>();
             List<EntryStack> entries = new ArrayList<>();
@@ -42,27 +42,27 @@ public class DefaultStoneCuttingDisplay implements RecipeDisplay {
         }).collect(Collectors.toList());
         }).collect(Collectors.toList());
         this.output = Collections.singletonList(EntryStack.create(output));
         this.output = Collections.singletonList(EntryStack.create(output));
     }
     }
-
+    
     @Override
     @Override
     public Optional<Identifier> getRecipeLocation() {
     public Optional<Identifier> getRecipeLocation() {
         return Optional.ofNullable(display).map(CuttingRecipe::getId);
         return Optional.ofNullable(display).map(CuttingRecipe::getId);
     }
     }
-
+    
     @Override
     @Override
     public List<List<EntryStack>> getInputEntries() {
     public List<List<EntryStack>> getInputEntries() {
         return inputs;
         return inputs;
     }
     }
-
+    
     @Override
     @Override
     public List<EntryStack> getOutputEntries() {
     public List<EntryStack> getOutputEntries() {
         return output;
         return output;
     }
     }
-
+    
     @Override
     @Override
     public Identifier getRecipeCategory() {
     public Identifier getRecipeCategory() {
         return DefaultPlugin.STONE_CUTTING;
         return DefaultPlugin.STONE_CUTTING;
     }
     }
-
+    
     @Override
     @Override
     public List<List<EntryStack>> getRequiredEntries() {
     public List<List<EntryStack>> getRequiredEntries() {
         return getInputEntries();
         return getInputEntries();

+ 6 - 6
src/main/java/me/shedaniel/rei/plugin/stripping/DefaultStrippingCategory.java

@@ -24,22 +24,22 @@ import java.util.List;
 import java.util.function.Supplier;
 import java.util.function.Supplier;
 
 
 public class DefaultStrippingCategory implements RecipeCategory<DefaultStrippingDisplay> {
 public class DefaultStrippingCategory implements RecipeCategory<DefaultStrippingDisplay> {
-
+    
     @Override
     @Override
     public Identifier getIdentifier() {
     public Identifier getIdentifier() {
         return DefaultPlugin.STRIPPING;
         return DefaultPlugin.STRIPPING;
     }
     }
-
+    
     @Override
     @Override
     public EntryStack getLogo() {
     public EntryStack getLogo() {
         return EntryStack.create(Items.IRON_AXE);
         return EntryStack.create(Items.IRON_AXE);
     }
     }
-
+    
     @Override
     @Override
     public String getCategoryName() {
     public String getCategoryName() {
         return I18n.translate("category.rei.stripping");
         return I18n.translate("category.rei.stripping");
     }
     }
-
+    
     @Override
     @Override
     public List<Widget> setupDisplay(Supplier<DefaultStrippingDisplay> recipeDisplaySupplier, Rectangle bounds) {
     public List<Widget> setupDisplay(Supplier<DefaultStrippingDisplay> recipeDisplaySupplier, Rectangle bounds) {
         Point startPoint = new Point(bounds.getCenterX() - 41, bounds.getCenterY() - 13);
         Point startPoint = new Point(bounds.getCenterX() - 41, bounds.getCenterY() - 13);
@@ -55,10 +55,10 @@ public class DefaultStrippingCategory implements RecipeCategory<DefaultStripping
         widgets.add(EntryWidget.create(startPoint.x + 61, startPoint.y + 5).entry(recipeDisplaySupplier.get().getOut()).noBackground());
         widgets.add(EntryWidget.create(startPoint.x + 61, startPoint.y + 5).entry(recipeDisplaySupplier.get().getOut()).noBackground());
         return widgets;
         return widgets;
     }
     }
-
+    
     @Override
     @Override
     public int getDisplayHeight() {
     public int getDisplayHeight() {
         return 36;
         return 36;
     }
     }
-
+    
 }
 }

+ 2 - 0
src/main/resources/assets/roughlyenoughitems/lang/en_us.json

@@ -94,6 +94,7 @@
   "config.roughlyenoughitems.technical": "Technical",
   "config.roughlyenoughitems.technical": "Technical",
   "config.roughlyenoughitems.performance": "Performance",
   "config.roughlyenoughitems.performance": "Performance",
   "config.roughlyenoughitems.cheating": "Cheating:",
   "config.roughlyenoughitems.cheating": "Cheating:",
+  "config.roughlyenoughitems.smooth_scrolling": "Smooth Scrolling Settings",
   "config.roughlyenoughitems.recipeKeybind": "Show Recipe:",
   "config.roughlyenoughitems.recipeKeybind": "Show Recipe:",
   "config.roughlyenoughitems.hideKeybind": "Hide/Show REI:",
   "config.roughlyenoughitems.hideKeybind": "Hide/Show REI:",
   "config.roughlyenoughitems.usageKeybind": "Show Uses:",
   "config.roughlyenoughitems.usageKeybind": "Show Uses:",
@@ -148,6 +149,7 @@
   "config.roughlyenoughitems.weatherCommand": "Weather Command:",
   "config.roughlyenoughitems.weatherCommand": "Weather Command:",
   "config.roughlyenoughitems.itemListOrdering": "Entry List Ordering:",
   "config.roughlyenoughitems.itemListOrdering": "Entry List Ordering:",
   "config.roughlyenoughitems.list_ordering_button": "%s [%s]",
   "config.roughlyenoughitems.list_ordering_button": "%s [%s]",
+  "config.roughlyenoughitems.newFastEntryRendering": "Faster Entry Rendering:",
   "config.roughlyenoughitems.recipeScreenType": "Recipe Screen Type:",
   "config.roughlyenoughitems.recipeScreenType": "Recipe Screen Type:",
   "config.roughlyenoughitems.recipeScreenType.config": "Recipe Screen Type: %s",
   "config.roughlyenoughitems.recipeScreenType.config": "Recipe Screen Type: %s",
   "config.roughlyenoughitems.recipeScreenType.unset": "Not Set",
   "config.roughlyenoughitems.recipeScreenType.unset": "Not Set",