diff --git a/src/api/java/yalter/mousetweaks/api/IMTModGuiContainer2.java b/src/api/java/yalter/mousetweaks/api/IMTModGuiContainer2.java new file mode 100644 index 00000000000..e9618b22984 --- /dev/null +++ b/src/api/java/yalter/mousetweaks/api/IMTModGuiContainer2.java @@ -0,0 +1,87 @@ +package yalter.mousetweaks.api; + +import net.minecraft.inventory.Container; +import net.minecraft.inventory.Slot; + +/** + * This is the interface you want to implement in your GuiScreen to make it compatible with Mouse Tweaks. + * If this interface is not enough (for example, you need a custom slot click function, or if you use a custom Container + * which happens to be incompatible), check IMTModGuiContainer2Ex instead. + * If you just need to disable Mouse Tweaks or the wheel tweak, see the MouseTweaksIgnore + * or the MouseTweaksDisableWheelTweak annotations. + */ +public interface IMTModGuiContainer2 { + /** + * If you want to disable Mouse Tweaks in your GuiScreen, return true from this method. + * + * @return True if Mouse Tweaks should be disabled, false otherwise. + */ + boolean MT_isMouseTweaksDisabled(); + + /** + * If you want to disable the Wheel Tweak in your GuiScreen, return true from this method. + * + * @return True if the Wheel Tweak should be disabled, false otherwise. + */ + boolean MT_isWheelTweakDisabled(); + + /** + * Returns the Container. + * + * @return Container that is currently in use. + */ + Container MT_getContainer(); + + /** + * Returns the Slot that is currently selected by the player, or null if no Slot is selected. + * + * @return Slot that is located under the mouse, or null if no Slot it currently under the mouse. + */ + Slot MT_getSlotUnderMouse(); + + /** + * Return true if the given Slot behaves like the vanilla crafting output slots (inside the crafting table, + * or the furnace output slot, or the anvil output slot, etc.). These slots are handled differently by Mouse Tweaks. + * + * @param slot the slot to check + * @return True if slot is a crafting output slot. + */ + boolean MT_isCraftingOutput(Slot slot); + + /** + * Return true if the given Slot should be ignored by Mouse Tweaks. Examples of ignored slots are the item select + * slots and the Destroy Item slot in the vanilla creative inventory. + * + * @param slot the slot to check + * @return Tru if slot should be ignored by Mouse Tweaks. + */ + boolean MT_isIgnored(Slot slot); + + /** + * If your container has an RMB dragging functionality (like vanilla containers), disable it inside this method. + * This method is called every frame (render tick), which is after all mouseClicked / mouseClickMove / mouseReleased + * events are handled (although note these events are handled every game tick, which is far less frequent than every + * render tick).

+ *

+ * If true is returned from this method, Mouse Tweaks (after checking other conditions like isIgnored) will click + * the slot on which the right mouse button was initially pressed (in most cases this is the slot currently under + * mouse). This is needed because the vanilla RMB dragging functionality prevents the initial slot click.

+ *

+ * For vanilla containers this method looks like this: + *

+     * this.ignoreMouseUp = true;
+     *
+     * if (this.dragSplitting) {
+     *     if (this.dragSplittingButton == 1) {
+     *         this.dragSplitting = false;
+     *         return true;
+     *     }
+     * }
+     *
+     * return false;
+     * 
+ * + * @return True if Mouse Tweaks should click the slot on which the RMB was pressed. + */ + boolean MT_disableRMBDraggingFunctionality(); +} \ No newline at end of file diff --git a/src/api/java/yalter/mousetweaks/api/MouseTweaksIgnore.java b/src/api/java/yalter/mousetweaks/api/MouseTweaksIgnore.java deleted file mode 100644 index 78737d128b6..00000000000 --- a/src/api/java/yalter/mousetweaks/api/MouseTweaksIgnore.java +++ /dev/null @@ -1,14 +0,0 @@ -package yalter.mousetweaks.api; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Put this on your GuiScreen to disable Mouse Tweaks. - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.TYPE) -public @interface MouseTweaksIgnore { -} \ No newline at end of file diff --git a/src/main/java/appeng/client/gui/AEBaseGui.java b/src/main/java/appeng/client/gui/AEBaseGui.java index 7b76eed1f30..f919874884b 100644 --- a/src/main/java/appeng/client/gui/AEBaseGui.java +++ b/src/main/java/appeng/client/gui/AEBaseGui.java @@ -72,7 +72,7 @@ import org.lwjgl.input.Keyboard; import org.lwjgl.input.Mouse; import org.lwjgl.opengl.GL11; -import yalter.mousetweaks.api.MouseTweaksIgnore; +import yalter.mousetweaks.api.IMTModGuiContainer2; import java.awt.*; import java.io.IOException; @@ -85,9 +85,8 @@ import static appeng.integration.modules.jei.JEIPlugin.aeGuiHandler; import static appeng.integration.modules.jei.JEIPlugin.runtime; - -@MouseTweaksIgnore -public abstract class AEBaseGui extends GuiContainer { +@Optional.Interface(iface = "yalter.mousetweaks.api.IMTModGuiContainer2", modid = "mousetweaks") +public abstract class AEBaseGui extends GuiContainer implements IMTModGuiContainer2 { private final List meSlots = new ArrayList<>(); // drag y private final Set drag_click = new HashSet<>(); @@ -950,10 +949,42 @@ public void drawSlot(Slot s) { this.zLevel = 0.0F; this.itemRender.zLevel = 0.0F; + boolean wasDragSplitting = this.dragSplitting; + this.dragSplitting = false; // to prevent the vanilla slot renderer from rendering the stack count during drag splitting, we're re-enabling it later + // Annoying but easier than trying to splice into render item super.drawSlot(s); - this.stackSizeRenderer.renderStackSize(this.fontRenderer, AEItemStack.fromItemStack(appEngSlot.getDisplayStack()), s.xPos, s.yPos); + ItemStack stackInSlot = ((AppEngSlot)s).getDisplayStack(); + ItemStack stackUnderCursor = this.mc.player.inventory.getItemStack(); + + if (wasDragSplitting + && this.dragSplittingSlots.contains(s) + && this.dragSplittingSlots.size() > 1 + && !stackUnderCursor.isEmpty()) { + if (Container.canAddItemToSlot(s, stackUnderCursor, true) && this.inventorySlots.canDragIntoSlot(s)) + { + drawRect(s.xPos, s.yPos, s.xPos + 16, s.yPos + 16, -2130706433); + + stackInSlot = stackUnderCursor.copy(); + Container.computeStackSize(this.dragSplittingSlots, this.dragSplittingLimit, stackInSlot, s.getStack().isEmpty() ? 0 : s.getStack().getCount()); + int k = Math.min(stackInSlot.getMaxStackSize(), s.getItemStackLimit(stackInSlot)); + + if (stackInSlot.getCount() > k) + { + stackInSlot.setCount(k); + } + } + else + { + this.dragSplittingSlots.remove(s); + this.updateDragSplitting(); + } + } + + this.dragSplitting = wasDragSplitting; + this.stackSizeRenderer.renderStackSize(this.fontRenderer, AEItemStack.fromItemStack(stackInSlot), s.xPos, s.yPos); + return; } else { super.drawSlot(s); @@ -988,4 +1019,80 @@ protected void setScrollBar(final GuiScrollbar myScrollBar) { protected List getMeSlots() { return this.meSlots; } + + // TODO: remove this when refactoring slot rendering + private void updateDragSplitting() + { + ItemStack itemstack = this.mc.player.inventory.getItemStack(); + + if (!itemstack.isEmpty() && this.dragSplitting) + { + if (this.dragSplittingLimit == 2) + { + this.dragSplittingRemnant = itemstack.getMaxStackSize(); + } + else + { + this.dragSplittingRemnant = itemstack.getCount(); + + for (Slot slot : this.dragSplittingSlots) + { + ItemStack itemstack1 = itemstack.copy(); + ItemStack itemstack2 = slot.getStack(); + int i = itemstack2.isEmpty() ? 0 : itemstack2.getCount(); + Container.computeStackSize(this.dragSplittingSlots, this.dragSplittingLimit, itemstack1, i); + int j = Math.min(itemstack1.getMaxStackSize(), slot.getItemStackLimit(itemstack1)); + + if (itemstack1.getCount() > j) + { + itemstack1.setCount(j); + } + + this.dragSplittingRemnant -= itemstack1.getCount() - i; + } + } + } + } + + @Override + @Optional.Method(modid = "mousetweaks") + public boolean MT_isMouseTweaksDisabled() { + return true; + } + + @Override + @Optional.Method(modid = "mousetweaks") + public boolean MT_isWheelTweakDisabled() { + return true; + } + + @Override + @Optional.Method(modid = "mousetweaks") + public Container MT_getContainer() { + return this.inventorySlots; + } + + @Override + @Optional.Method(modid = "mousetweaks") + public Slot MT_getSlotUnderMouse() { + return getSlotUnderMouse(); + } + + @Override + @Optional.Method(modid = "mousetweaks") + public boolean MT_isCraftingOutput(Slot slot) { + return slot instanceof SlotOutput || slot instanceof AppEngCraftingSlot; + } + + @Override + @Optional.Method(modid = "mousetweaks") + public boolean MT_isIgnored(Slot slot) { + return true; + } + + @Override + @Optional.Method(modid = "mousetweaks") + public boolean MT_disableRMBDraggingFunctionality() { + return true; + } } diff --git a/src/main/java/appeng/client/gui/implementations/GuiMEMonitorable.java b/src/main/java/appeng/client/gui/implementations/GuiMEMonitorable.java index 5720a83a1e5..f413db00d54 100644 --- a/src/main/java/appeng/client/gui/implementations/GuiMEMonitorable.java +++ b/src/main/java/appeng/client/gui/implementations/GuiMEMonitorable.java @@ -467,6 +467,7 @@ protected void keyTyped(final char character, final int key) throws IOException } final boolean mouseInGui = this.isPointInRegion(0, 0, this.xSize, this.ySize, this.currentMouseX, this.currentMouseY); + final boolean wasSearchFieldFocused = this.searchField.isFocused(); if (this.isAutoFocus && !this.searchField.isFocused() && mouseInGui) { this.searchField.setFocused(true); @@ -478,6 +479,10 @@ protected void keyTyped(final char character, final int key) throws IOException // tell forge the key event is handled and should not be sent out this.keyHandled = mouseInGui; } else { + if (!wasSearchFieldFocused) { + // prevent unhandled keys (like shift) from focusing the search field + searchField.setFocused(false); + } super.keyTyped(character, key); } }