Files
Applied-Energistics-2/src/main/java/appeng/client/gui/widgets/Scrollbar.java
T

271 lines
7.7 KiB
Java

/*
* This file is part of Applied Energistics 2.
* Copyright (c) 2013 - 2014, AlgorithmX2, All rights reserved.
*
* Applied Energistics 2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Applied Energistics 2 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Applied Energistics 2. If not, see <http://www.gnu.org/licenses/lgpl>.
*/
package appeng.client.gui.widgets;
import appeng.client.gui.AEBaseScreen;
import com.mojang.blaze3d.matrix.MatrixStack;
import net.minecraft.client.gui.AbstractGui;
import net.minecraft.client.renderer.Rectangle2d;
import net.minecraft.util.ResourceLocation;
import java.time.Duration;
public class Scrollbar extends AbstractGui implements IScrollSource {
/**
* Width of the scrollbar handle sprite in the source texture.
*/
private static final int HANDLE_WIDTH = 12;
/**
* Height of the scrollbar handle sprite in the source texture.
*/
private static final int HANDLE_HEIGHT = 15;
/**
* Texture containing the scrollbar handle sprites.
*/
private static final ResourceLocation TEXTURE = new ResourceLocation("minecraft",
"textures/gui/container/creative_inventory/tabs.png");
/**
* Rectangle in the source texture that contains the sprite for an enabled
* handle.
*/
private static final Rectangle2d ENABLED = new Rectangle2d(232, 0, HANDLE_WIDTH, HANDLE_HEIGHT);
/**
* Rectangle in the source texture that contains the sprite for a disabled
* handle.
*/
private static final Rectangle2d DISABLED = new Rectangle2d(232 + HANDLE_WIDTH, 0, HANDLE_WIDTH, HANDLE_HEIGHT);
/**
* The screen x-coordinate of the scrollbar's inner track.
*/
private int displayX = 0;
/**
* The screen y-coordinate of the scrollbar's inner track.
*/
private int displayY = 0;
/**
* The inner width of the scrollbar track.
*/
private int width = HANDLE_WIDTH;
/**
* The inner height of the scrollbar track.
*/
private int height = 16;
private int pageSize = 1;
private int maxScroll = 0;
private int minScroll = 0;
private int currentScroll = 0;
/**
* True if the scrollbar's handle is currently being dragged.
*/
private boolean dragging;
private final EventRepeater eventRepeater = new EventRepeater(
Duration.ofMillis(250),
Duration.ofMillis(150)
);
/**
* Draws the handle of the scrollbar.
* <p>
* The GUI is assumed to already contain a prebaked scrollbar track in its
* background.
*/
public void draw(MatrixStack matrices, final AEBaseScreen<?> g) {
setBlitOffset(g.getBlitOffset());
// Draw the track (nice for debugging)
// fill(matrices, displayX, displayY, this.displayX + width, this.displayY + height, 0xffff0000);
g.bindTexture(TEXTURE);
int yOffset;
Rectangle2d sourceRect;
if (this.getRange() == 0) {
yOffset = 0;
sourceRect = DISABLED;
} else {
yOffset = getHandleYOffset();
sourceRect = ENABLED;
}
blit(matrices, this.displayX, this.displayY + yOffset, sourceRect.getX(), sourceRect.getY(),
sourceRect.getWidth(), sourceRect.getHeight());
}
/**
* Returns the y-position of the scrollbar handle in relation to the upper edge
* of the scrollbar's track.
*/
private int getHandleYOffset() {
int availableHeight = this.height - HANDLE_HEIGHT;
return (this.currentScroll - this.minScroll) * availableHeight / this.getRange();
}
private int getRange() {
return this.maxScroll - this.minScroll;
}
public int getLeft() {
return this.displayX;
}
public Scrollbar setLeft(final int v) {
this.displayX = v;
return this;
}
public int getTop() {
return this.displayY;
}
public Scrollbar setTop(final int v) {
this.displayY = v;
return this;
}
public int getWidth() {
return this.width;
}
public Scrollbar setWidth(final int v) {
this.width = v;
return this;
}
public int getHeight() {
return this.height;
}
public Scrollbar setHeight(final int v) {
this.height = v;
return this;
}
public void setRange(final int min, final int max, final int pageSize) {
this.minScroll = min;
this.maxScroll = max;
this.pageSize = pageSize;
if (this.minScroll > this.maxScroll) {
this.maxScroll = this.minScroll;
}
this.applyRange();
}
private void applyRange() {
this.currentScroll = Math.max(Math.min(this.currentScroll, this.maxScroll), this.minScroll);
}
@Override
public int getCurrentScroll() {
return this.currentScroll;
}
public boolean mouseDown(double x, double y) {
this.dragging = false;
// Clicks to the left or right of the scrollbar don't do anything
if (x < displayX || x >= displayX + width) {
return false;
}
// Clicks to the top or bottom don't do anything either
int relY = (int) Math.round(y - displayY);
if (relY < 0 || relY >= height) {
return false;
}
int handleYOffset = getHandleYOffset();
if (relY < handleYOffset) {
// Clicks above the handle will page up, repeatedly
repeatPageUp();
eventRepeater.repeat(this::repeatPageUp);
} else if (relY < handleYOffset + HANDLE_HEIGHT) {
// Clicks on the handle will initiate dragging it
this.dragging = true;
} else {
// Clicks below the handle will page down, repeatedly
repeatPageDown();
eventRepeater.repeat(this::repeatPageDown);
}
return true;
}
public boolean mouseUp(double x, double y) {
this.dragging = false;
this.eventRepeater.stop();
return false;
}
public void mouseDragged(double x, double y) {
if (this.getRange() == 0 || !this.dragging || this.eventRepeater.isRepeating()) {
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();
}
}
public void wheel(double delta) {
delta = Math.max(Math.min(-delta, 1), -1);
this.currentScroll += delta * this.pageSize;
this.applyRange();
}
/**
* Ticks the scrollbar for the purposes of input-repeats (since mouse-downs are not repeat-triggered),
* used to repeatedly page-up or page-down when the mouse is held in the area above or below the scrollbar handle.
*/
public void tick() {
this.eventRepeater.tick();
}
private void repeatPageUp() {
System.out.println("REPEAT PAGE UP");
this.currentScroll -= this.pageSize;
this.applyRange();
}
private void repeatPageDown() {
System.out.println("REPEAT PAGE DOWN");
this.currentScroll += this.pageSize;
this.applyRange();
}
}