diff --git a/src/main/java/ru/windcorp/progressia/test/inv/HandSlots.java b/src/main/java/ru/windcorp/progressia/test/inv/HandSlots.java
new file mode 100644
index 0000000..005a36b
--- /dev/null
+++ b/src/main/java/ru/windcorp/progressia/test/inv/HandSlots.java
@@ -0,0 +1,110 @@
+/*
+ * Progressia
+ * Copyright (C) 2020-2021 Wind Corporation and contributors
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+package ru.windcorp.progressia.test.inv;
+
+import glm.vec._2.i.Vec2i;
+import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
+import ru.windcorp.progressia.client.graphics.backend.InputTracker;
+import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
+import ru.windcorp.progressia.client.graphics.gui.Component;
+import ru.windcorp.progressia.client.graphics.model.Renderable;
+import ru.windcorp.progressia.client.graphics.model.ShapeRenderHelper;
+
+public class HandSlots extends Component {
+
+ private final SlotComponent left;
+ private final SlotComponent right;
+
+ /**
+ * Right is 0, left is 1
+ */
+ private float selection = 0;
+ private static final float ANIMATION_SPEED = 10f;
+
+ public HandSlots(String name, SlotComponent left, SlotComponent right) {
+ super(name);
+ this.left = left;
+ this.right = right;
+
+ addChild(left);
+ addChild(right);
+ setLayout(null);
+
+ centerAtOrigin(left);
+ centerAtOrigin(right);
+ layoutSelf();
+ }
+
+ private static void centerAtOrigin(Component component) {
+ Vec2i size = component.getPreferredSize();
+ component.setBounds(-size.x / 2, -size.y / 2, size);
+ }
+
+ @Override
+ protected void assembleChildren(RenderTarget target) {
+
+ Renderable leftRenderable = left.assembleToRenderable();
+ Renderable rightRenderable = right.assembleToRenderable();
+
+ target.addCustomRenderer(renderer -> {
+
+ tickAnimation();
+
+ renderer.pushTransform().translate(
+ (float) InputTracker.getCursorX(),
+ (float) InputTracker.getCursorY(),
+ 0
+ );
+
+ if (selection > 0.5) {
+ renderHand(renderer, leftRenderable, selection, -1);
+ renderHand(renderer, rightRenderable, 1 - selection, +1);
+ } else {
+ renderHand(renderer, rightRenderable, 1 - selection, +1);
+ renderHand(renderer, leftRenderable, selection, -1);
+ }
+
+ renderer.popTransform();
+
+ });
+
+ }
+
+ private float stretch(float t, float zero, float one) {
+ return zero * (1 - t) + one * t;
+ }
+
+ private void renderHand(ShapeRenderHelper renderer, Renderable renderable, float selected, float direction) {
+
+ float offsetX = direction * stretch(selected, 40, 0);
+ float offsetY = direction * stretch(selected, 30, 0);
+ float scale = selected < 0.5 ? stretch(selected * 2, 0.6f, 1.0f) : 1;
+
+ renderer.pushTransform().translate(offsetX, offsetY, 0).scale(scale);
+ renderable.render(renderer);
+ renderer.popTransform();
+
+ }
+
+ private void tickAnimation() {
+ float desired = InventoryScreen.isLeftHandSelected() ? 1 : 0;
+ float difference = selection - desired;
+ selection += difference * (1 - Math.exp(ANIMATION_SPEED * GraphicsInterface.getFrameLength()));
+ }
+
+}
diff --git a/src/main/java/ru/windcorp/progressia/test/inv/InventoryScreen.java b/src/main/java/ru/windcorp/progressia/test/inv/InventoryScreen.java
index 08aa9fa..a3c7275 100644
--- a/src/main/java/ru/windcorp/progressia/test/inv/InventoryScreen.java
+++ b/src/main/java/ru/windcorp/progressia/test/inv/InventoryScreen.java
@@ -22,66 +22,47 @@ import java.util.function.Supplier;
import org.lwjgl.glfw.GLFW;
-import glm.vec._2.i.Vec2i;
import ru.windcorp.progressia.client.graphics.Colors;
+import ru.windcorp.progressia.client.graphics.backend.GraphicsInterface;
import ru.windcorp.progressia.client.graphics.backend.InputTracker;
-import ru.windcorp.progressia.client.graphics.flat.RenderTarget;
import ru.windcorp.progressia.client.graphics.gui.BasicButton;
import ru.windcorp.progressia.client.graphics.gui.Component;
import ru.windcorp.progressia.client.graphics.gui.Components;
-import ru.windcorp.progressia.client.graphics.gui.Group;
-import ru.windcorp.progressia.client.graphics.gui.Layout;
import ru.windcorp.progressia.client.graphics.gui.Panel;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutAlign;
import ru.windcorp.progressia.client.graphics.gui.layout.LayoutFill;
import ru.windcorp.progressia.client.graphics.input.KeyEvent;
+import ru.windcorp.progressia.client.graphics.input.WheelScrollEvent;
import ru.windcorp.progressia.client.graphics.input.bus.InputListener;
-import ru.windcorp.progressia.client.graphics.model.Renderable;
+import ru.windcorp.progressia.common.Units;
import ru.windcorp.progressia.common.world.entity.EntityDataPlayer;
import ru.windcorp.progressia.common.world.item.ItemContainer;
import ru.windcorp.progressia.common.world.item.ItemSlot;
import ru.windcorp.progressia.common.world.item.Items;
public class InventoryScreen extends Component {
+
+ private static final double MIN_PICK_ALL_DELAY = Units.get("0.5 s");
- public static class CursorFollower extends Component {
-
- public CursorFollower(Component child) {
- super("CursorFollower");
- addChild(child);
- setLayout(null);
-
- Vec2i size = child.getPreferredSize();
- child.setBounds(-size.x / 2, -size.y / 2, size);
- layoutSelf();
- }
-
- @Override
- protected void assembleChildren(RenderTarget target) {
- Renderable renderable = getChildren().get(0).assembleToRenderable();
-
- target.addCustomRenderer(renderer -> {
- renderer.pushTransform().translate(
- (float) InputTracker.getCursorX(),
- (float) InputTracker.getCursorY(),
- 0
- );
-
- renderable.render(renderer);
-
- renderer.popTransform();
-
- });
- }
-
+ public static boolean isLeftHandSelected() {
+ return InputTracker.isKeyPressed(GLFW.GLFW_KEY_LEFT_CONTROL)
+ || InputTracker.isKeyPressed(GLFW.GLFW_KEY_RIGHT_CONTROL);
}
private final ItemContainer leftHand;
private final ItemContainer rightHand;
+ private final InventoryComponent mainInventory;
+
+ private double lastLeftClick = Double.NEGATIVE_INFINITY;
+ private ItemSlot lastLeftClickSlot = null;
public InventoryScreen(String name, InventoryComponent mainInventory, EntityDataPlayer player) {
super(name);
+ this.mainInventory = mainInventory;
+ this.leftHand = player.getLeftHand();
+ this.rightHand = player.getRightHand();
+
setLayout(new LayoutFill(0));
addChild(new Panel(name + ".Background", new LayoutAlign(10), Colors.toVector(0x66000000), null));
@@ -90,47 +71,14 @@ public class InventoryScreen extends Component {
mainInventoryPanel.addChild(mainInventory);
addChild(Components.center(mainInventoryPanel));
- this.leftHand = player.getLeftHand();
- this.rightHand = player.getRightHand();
- addChild(new CursorFollower(createHands(name, leftHand, rightHand)));
-
- addListeners(mainInventory);
- }
-
- private Component createHands(String name, ItemContainer leftHand, ItemContainer rightHand) {
-
SlotComponent leftComponent = new SlotComponent(name + ".HandLeft", leftHand, 0);
SlotComponent rightComponent = new SlotComponent(name + ".HandRight", rightHand, 0);
+
+ addChild(new HandSlots(name + ".Hands", leftComponent, rightComponent));
- final int gap = 15;
- final int offset = 60;
-
- Component hands = new Group(name + ".Hands", null, leftComponent, rightComponent);
- hands.setLayout(new Layout() {
-
- @Override
- public void layout(Component c) {
- Vec2i leftSize = leftComponent.getPreferredSize();
- Vec2i rightSize = rightComponent.getPreferredSize();
-
- leftComponent.setBounds(c.getX(), c.getY(), leftSize);
- rightComponent.setBounds(c.getX() + leftSize.x + gap, c.getY() + offset, rightSize);
- }
-
- @Override
- public Vec2i calculatePreferredSize(Component c) {
- Vec2i leftSize = leftComponent.getPreferredSize();
- Vec2i rightSize = rightComponent.getPreferredSize();
-
- return new Vec2i(
- leftSize.x + gap + rightSize.x,
- Math.max(leftSize.y + offset, rightSize.y + offset)
- );
- }
-
- });
-
- return hands;
+ addListeners(mainInventory);
+
+ mainInventory.focusNext();
}
private void addListeners(InventoryComponent mainInventory) {
@@ -138,18 +86,14 @@ public class InventoryScreen extends Component {
ItemSlot left = leftHand.getSlot(0);
ItemSlot right = rightHand.getSlot(0);
- Supplier handSlot = () -> {
- boolean hasCtrl = InputTracker.isKeyPressed(GLFW.GLFW_KEY_LEFT_CONTROL)
- || InputTracker.isKeyPressed(GLFW.GLFW_KEY_RIGHT_CONTROL);
-
- return hasCtrl ? left : right;
- };
+ Supplier handSlot = () -> isLeftHandSelected() ? left : right;
Consumer pickAll = createPickAllAction(handSlot);
for (DecoratedSlotComponent component : mainInventory.getSlots()) {
component.addAction(pickAll);
component.addListener(KeyEvent.class, createRMBAction(component.getSlot(), handSlot));
+ component.addListener(WheelScrollEvent.class, createWheelAction(component.getSlot(), handSlot));
}
}
@@ -158,18 +102,54 @@ public class InventoryScreen extends Component {
ItemSlot handSlot = handSlotChooser.get();
ItemSlot invSlot = ((DecoratedSlotComponent) button).getSlot();
-
- if (Items.pour(handSlot, invSlot) == 0) {
- if (!Items.swap(handSlot, invSlot)) {
- return;
- }
+
+ boolean success = false;
+
+ double now = GraphicsInterface.getTime();
+ if (lastLeftClickSlot == invSlot && now - lastLeftClick < MIN_PICK_ALL_DELAY) {
+
+ lastLeftClickSlot = null;
+ lastLeftClick = Double.NEGATIVE_INFINITY;
+
+ pickAll(handSlot);
+
+ success = true;
+
+ } else {
+ lastLeftClick = now;
+ lastLeftClickSlot = invSlot;
+ }
+
+ if (!success && !leftHand.getSlot(0).isEmpty() && rightHand.getSlot(0).isEmpty()) {
+ success = Items.pour(leftHand.getSlot(0), invSlot) != 0;
+ }
+
+ if (!success) {
+ success = Items.pour(handSlot, invSlot) != 0;
+ }
+
+ if (!success) {
+ success = Items.swap(handSlot, invSlot);
}
- requestReassembly();
+ if (success) {
+ requestReassembly();
+ }
};
}
+ private void pickAll(ItemSlot handSlot) {
+ for (DecoratedSlotComponent component : mainInventory.getSlots()) {
+
+ Items.pour(component.getSlot(), handSlot);
+ if (handSlot.isEmpty()) {
+ break;
+ }
+
+ }
+ }
+
private InputListener createRMBAction(ItemSlot invSlot, Supplier handSlotChooser) {
return input -> {
@@ -201,5 +181,27 @@ public class InventoryScreen extends Component {
};
}
+
+
+ private InputListener createWheelAction(ItemSlot invSlot, Supplier handSlotChooser) {
+ return input -> {
+
+ if (!input.hasVerticalMovement()) {
+ return false;
+ }
+
+ ItemSlot handSlot = handSlotChooser.get();
+
+ ItemSlot from = input.isDown() ? handSlot : invSlot;
+ ItemSlot into = input.isDown() ? invSlot : handSlot;
+
+ if (Items.pour(from, into, 1) != 0) {
+ requestReassembly();
+ }
+
+ return true;
+
+ };
+ }
}