Fixes #4731: Take the position where the user clicked the handle into account when calculating the new scrollbar position.

Also fixes: The scrollbar did not subtract the handle height when determining the available space for moving the handle, thus introducing drift the further down a user scrolled.
Also fixes: The scrollbar did not resize it's trackbar when the ME inventory screens were resized and the number of rows changed, same for craft confirm.
This commit is contained in:
Sebastian Hartte
2020-09-13 23:12:59 +02:00
parent d87ff9d1e7
commit 38244000c9
4 changed files with 46 additions and 12 deletions
@@ -97,6 +97,8 @@ public class CraftConfirmScreen extends AEBaseScreen<CraftConfirmContainer> {
addButton(new Button(this.guiLeft + 6, this.guiTop + this.ySize - 25, 50, 20, GuiText.Cancel.text(), addButton(new Button(this.guiLeft + 6, this.guiTop + this.ySize - 25, 50, 20, GuiText.Cancel.text(),
btn -> subGui.goBack())); btn -> subGui.goBack()));
this.setScrollBar();
} }
@Override @Override
@@ -71,8 +71,7 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
public InterfaceTerminalScreen(InterfaceTerminalContainer container, PlayerInventory playerInventory, public InterfaceTerminalScreen(InterfaceTerminalContainer container, PlayerInventory playerInventory,
ITextComponent title) { ITextComponent title) {
super(container, playerInventory, title); super(container, playerInventory, title);
final Scrollbar scrollbar = new Scrollbar(); this.setScrollBar(new Scrollbar().setLeft(175).setTop(18).setHeight(106));
this.setScrollBar(scrollbar);
this.xSize = 195; this.xSize = 195;
this.ySize = 222; this.ySize = 222;
} }
@@ -81,10 +80,6 @@ public class InterfaceTerminalScreen extends AEBaseScreen<InterfaceTerminalConta
public void init() { public void init() {
super.init(); super.init();
this.getScrollBar().setLeft(175);
this.getScrollBar().setHeight(106);
this.getScrollBar().setTop(18);
this.searchField = new AETextField(this.font, this.guiLeft + 104, this.guiTop + 4, 65, 12); this.searchField = new AETextField(this.font, this.guiLeft + 104, this.guiTop + 4, 65, 12);
this.searchField.setEnableBackgroundDrawing(false); this.searchField.setEnableBackgroundDrawing(false);
this.searchField.setMaxStringLength(25); this.searchField.setMaxStringLength(25);
@@ -283,6 +283,8 @@ public class MEMonitorableScreen<T extends MEMonitorableContainer> extends AEBas
craftingGridOffsetX -= 25; craftingGridOffsetX -= 25;
craftingGridOffsetY -= 6; craftingGridOffsetY -= 6;
this.setScrollBar();
} }
@Override @Override
@@ -25,9 +25,20 @@ import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.gui.AbstractGui; import net.minecraft.client.gui.AbstractGui;
import net.minecraft.client.renderer.Rectangle2d; import net.minecraft.client.renderer.Rectangle2d;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.MathHelper;
import appeng.client.gui.AEBaseScreen; import appeng.client.gui.AEBaseScreen;
/**
* Implements a vertical scrollbar using Vanilla's scrollbar handle texture from
* the creative tab.
* <p>
* 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 { 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. * True if the scrollbar's handle is currently being dragged.
*/ */
private boolean dragging; 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)); 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. * of the scrollbar's track.
*/ */
private int getHandleYOffset() { private int getHandleYOffset() {
if (getRange() == 0) {
return 0;
}
int availableHeight = this.height - HANDLE_HEIGHT; int availableHeight = this.height - HANDLE_HEIGHT;
return (this.currentScroll - this.minScroll) * availableHeight / this.getRange(); return (this.currentScroll - this.minScroll) * availableHeight / this.getRange();
} }
@@ -203,6 +223,11 @@ public class Scrollbar extends AbstractGui implements IScrollSource {
return false; return false;
} }
// Do nothing when there's no range, but swallow the event
if (getRange() == 0) {
return true;
}
int handleYOffset = getHandleYOffset(); int handleYOffset = getHandleYOffset();
if (relY < handleYOffset) { if (relY < handleYOffset) {
@@ -213,6 +238,7 @@ public class Scrollbar extends AbstractGui implements IScrollSource {
} else if (relY < handleYOffset + HANDLE_HEIGHT) { } else if (relY < handleYOffset + HANDLE_HEIGHT) {
// Clicks on the handle will initiate dragging it // Clicks on the handle will initiate dragging it
this.dragging = true; this.dragging = true;
this.dragYOffset = relY - handleYOffset;
} else { } else {
// Clicks below the handle will page down, repeatedly // Clicks below the handle will page down, repeatedly
pageDown(); pageDown();
@@ -233,15 +259,24 @@ public class Scrollbar extends AbstractGui implements IScrollSource {
return; return;
} }
if (y > this.displayY && y <= this.displayY + this.height) { // Compute the position of the mouse (adjusted for where it grabbed the handle,
this.currentScroll = (int) (y - this.displayY); // so as if it grabbed
this.currentScroll = this.minScroll + ((this.currentScroll * 2 * this.getRange() / this.height)); // the upper edge of it) within the scrollable area of the track (minus the
this.currentScroll = (this.currentScroll + 1) >> 1; // handle height).
this.applyRange(); 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) { public void wheel(double delta) {
// Do nothing when there's no range
if (getRange() == 0) {
return;
}
delta = Math.max(Math.min(-delta, 1), -1); delta = Math.max(Math.min(-delta, 1), -1);
this.currentScroll += delta * this.pageSize; this.currentScroll += delta * this.pageSize;
this.applyRange(); this.applyRange();