diff --git a/src/main/java/appeng/client/gui/implementations/CraftConfirmScreen.java b/src/main/java/appeng/client/gui/implementations/CraftConfirmScreen.java index 771d58cda..76c14ff85 100644 --- a/src/main/java/appeng/client/gui/implementations/CraftConfirmScreen.java +++ b/src/main/java/appeng/client/gui/implementations/CraftConfirmScreen.java @@ -97,6 +97,8 @@ public class CraftConfirmScreen extends AEBaseScreen { addButton(new Button(this.guiLeft + 6, this.guiTop + this.ySize - 25, 50, 20, GuiText.Cancel.text(), btn -> subGui.goBack())); + + this.setScrollBar(); } @Override diff --git a/src/main/java/appeng/client/gui/implementations/InterfaceTerminalScreen.java b/src/main/java/appeng/client/gui/implementations/InterfaceTerminalScreen.java index 1bd3157e3..5d93481cb 100644 --- a/src/main/java/appeng/client/gui/implementations/InterfaceTerminalScreen.java +++ b/src/main/java/appeng/client/gui/implementations/InterfaceTerminalScreen.java @@ -71,8 +71,7 @@ public class InterfaceTerminalScreen extends AEBaseScreen extends AEBas craftingGridOffsetX -= 25; craftingGridOffsetY -= 6; + this.setScrollBar(); + } @Override diff --git a/src/main/java/appeng/client/gui/widgets/Scrollbar.java b/src/main/java/appeng/client/gui/widgets/Scrollbar.java index b25b0e703..a580a2219 100644 --- a/src/main/java/appeng/client/gui/widgets/Scrollbar.java +++ b/src/main/java/appeng/client/gui/widgets/Scrollbar.java @@ -25,9 +25,20 @@ import com.mojang.blaze3d.matrix.MatrixStack; import net.minecraft.client.gui.AbstractGui; import net.minecraft.client.renderer.Rectangle2d; import net.minecraft.util.ResourceLocation; +import net.minecraft.util.math.MathHelper; import appeng.client.gui.AEBaseScreen; +/** + * Implements a vertical scrollbar using Vanilla's scrollbar handle texture from + * the creative tab. + *

+ * It is expected that the background of the UI contains a pre-baked scrollbar + * track border, and that the exact rectangle of that track is set on this + * object via {@link #setLeft(int)}, {@link #setTop(int)} and + * {@link #setHeight(int)}. While the width of the track can also be set, the + * drawn handle will use vanilla's sprite width (see {@link #HANDLE_WIDTH}. + */ public class Scrollbar extends AbstractGui implements IScrollSource { /** @@ -87,6 +98,12 @@ public class Scrollbar extends AbstractGui implements IScrollSource { * True if the scrollbar's handle is currently being dragged. */ private boolean dragging; + /** + * The y-coordinate relative to the upper edge of the scrollbar handle, where + * the user pressed the mouse button to drag. While dragging, this is applied as + * an offset to the effective scrollbar position. + */ + private int dragYOffset; private final EventRepeater eventRepeater = new EventRepeater(Duration.ofMillis(250), Duration.ofMillis(150)); @@ -124,6 +141,9 @@ public class Scrollbar extends AbstractGui implements IScrollSource { * of the scrollbar's track. */ private int getHandleYOffset() { + if (getRange() == 0) { + return 0; + } int availableHeight = this.height - HANDLE_HEIGHT; return (this.currentScroll - this.minScroll) * availableHeight / this.getRange(); } @@ -203,6 +223,11 @@ public class Scrollbar extends AbstractGui implements IScrollSource { return false; } + // Do nothing when there's no range, but swallow the event + if (getRange() == 0) { + return true; + } + int handleYOffset = getHandleYOffset(); if (relY < handleYOffset) { @@ -213,6 +238,7 @@ public class Scrollbar extends AbstractGui implements IScrollSource { } else if (relY < handleYOffset + HANDLE_HEIGHT) { // Clicks on the handle will initiate dragging it this.dragging = true; + this.dragYOffset = relY - handleYOffset; } else { // Clicks below the handle will page down, repeatedly pageDown(); @@ -233,15 +259,24 @@ public class Scrollbar extends AbstractGui implements IScrollSource { return; } - if (y > this.displayY && y <= this.displayY + this.height) { - this.currentScroll = (int) (y - this.displayY); - this.currentScroll = this.minScroll + ((this.currentScroll * 2 * this.getRange() / this.height)); - this.currentScroll = (this.currentScroll + 1) >> 1; - this.applyRange(); - } + // Compute the position of the mouse (adjusted for where it grabbed the handle, + // so as if it grabbed + // the upper edge of it) within the scrollable area of the track (minus the + // handle height). + double handleUpperEdgeY = y - this.displayY - this.dragYOffset; + double availableHeight = this.height - HANDLE_HEIGHT; + double position = MathHelper.clamp(handleUpperEdgeY / availableHeight, 0.0, 1.0); + + this.currentScroll = this.minScroll + (int) Math.round(position * this.getRange()); + this.applyRange(); } public void wheel(double delta) { + // Do nothing when there's no range + if (getRange() == 0) { + return; + } + delta = Math.max(Math.min(-delta, 1), -1); this.currentScroll += delta * this.pageSize; this.applyRange();