mirror of
https://github.com/GTNewHorizons/NotEnoughItems.git
synced 2026-11-15 09:44:44 +00:00
437 lines
15 KiB
Java
437 lines
15 KiB
Java
package codechicken.nei.scroll;
|
|
|
|
import java.awt.Color;
|
|
|
|
import org.lwjgl.opengl.GL11;
|
|
|
|
import codechicken.lib.vec.Rectangle4i;
|
|
import codechicken.nei.NEIClientUtils;
|
|
import codechicken.nei.drawable.DrawableBuilder;
|
|
import codechicken.nei.drawable.DrawableResource;
|
|
|
|
public class ScrollBar {
|
|
|
|
/** The minimum length of the scrollbar cursor. */
|
|
private static final int MINIMUM_THUMB_SIZE = 6;
|
|
|
|
private static final Color BACKGROUND_COLOR = new Color(0x90B1D4E0);
|
|
private static final Color THUMB_COLOR = new Color(0xF0145DA0);
|
|
private static final Color THUMB_SELECTED_COLOR = new Color(0xF02E8BC0);
|
|
|
|
public enum ScrollType {
|
|
HORIZONTAL,
|
|
VERTICAL
|
|
}
|
|
|
|
public enum OverflowType {
|
|
NONE,
|
|
AUTO,
|
|
SCROLL,
|
|
OVERLAY
|
|
}
|
|
|
|
public enum ScrollPlace {
|
|
START,
|
|
END
|
|
}
|
|
|
|
private ScrollType scrollType = ScrollType.VERTICAL;
|
|
private OverflowType overflowType = OverflowType.SCROLL;
|
|
private ScrollPlace scrollPlace = ScrollPlace.END;
|
|
private float handleClickOffset = -1;
|
|
|
|
private int trackWidth = 6;
|
|
|
|
private int thumbPaddingLeft = 0;
|
|
private int thumbPaddingRight = 0;
|
|
private int thumbPaddingTop = 0;
|
|
private int thumbPaddingBottom = 0;
|
|
|
|
private int trackPaddingLeft = 0;
|
|
private int trackPaddingRight = 0;
|
|
private int trackPaddingTop = 0;
|
|
private int trackPaddingBottom = 0;
|
|
|
|
private DrawableResource thumbTexture;
|
|
private int thumbSliceStart;
|
|
private int thumbSliceEnd;
|
|
|
|
private DrawableResource trackTexture;
|
|
private int trackSliceStart;
|
|
private int trackSliceEnd;
|
|
|
|
public static ScrollBar defaultScrollBar() {
|
|
return new ScrollBar();
|
|
}
|
|
|
|
public static ScrollBar defaultVerticalBar() {
|
|
return new ScrollBar().setTrackWidth(8)
|
|
.setTrackTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 29, 95, 8, 11).build(), 3, 4)
|
|
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 22, 96, 6, 9).build(), 3, 2)
|
|
.setThumbPadding(1, 1, 1, 1);
|
|
}
|
|
|
|
public static ScrollBar defaultHorizontalBar() {
|
|
return new ScrollBar().setTrackWidth(8).setOverflowType(OverflowType.SCROLL)
|
|
.setTrackTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 0, 97, 11, 8).build(), 3, 4)
|
|
.setThumbTexture(new DrawableBuilder("nei:textures/nei_sprites.png", 12, 98, 9, 6).build(), 3, 2)
|
|
.setThumbPadding(1, 1, 1, 1);
|
|
}
|
|
|
|
/**
|
|
* Sets the size of the scrollbar without texture in the non-scrolling axis (width for vertical, height for
|
|
* horizontal).
|
|
*
|
|
* @param trackWidth
|
|
* @return
|
|
*/
|
|
public ScrollBar setTrackWidth(int trackWidth) {
|
|
this.trackWidth = trackWidth;
|
|
return this;
|
|
}
|
|
|
|
public ScrollBar setTrackPadding(int left, int top, int right, int bottom) {
|
|
this.trackPaddingLeft = left;
|
|
this.trackPaddingRight = right;
|
|
this.trackPaddingTop = top;
|
|
this.trackPaddingBottom = bottom;
|
|
return this;
|
|
}
|
|
|
|
public ScrollBar setThumbPadding(int left, int top, int right, int bottom) {
|
|
this.thumbPaddingLeft = left;
|
|
this.thumbPaddingRight = right;
|
|
this.thumbPaddingTop = top;
|
|
this.thumbPaddingBottom = bottom;
|
|
return this;
|
|
}
|
|
|
|
public int getTrackWidth() {
|
|
|
|
if (this.trackTexture != null) {
|
|
return this.scrollType == ScrollType.HORIZONTAL ? this.trackTexture.getHeight()
|
|
: this.trackTexture.getWidth();
|
|
}
|
|
|
|
return this.trackWidth;
|
|
}
|
|
|
|
protected int getThumbWidth() {
|
|
|
|
if (this.thumbTexture != null) {
|
|
return this.scrollType == ScrollType.HORIZONTAL ? this.thumbTexture.getHeight()
|
|
: this.thumbTexture.getWidth();
|
|
}
|
|
|
|
return getTrackWidth();
|
|
}
|
|
|
|
public ScrollBar setThumbTexture(DrawableResource texture, int sliceStart, int sliceEnd) {
|
|
this.thumbTexture = texture;
|
|
this.thumbSliceStart = sliceStart;
|
|
this.thumbSliceEnd = sliceEnd;
|
|
return this;
|
|
}
|
|
|
|
public ScrollBar setTrackTexture(DrawableResource texture, int sliceStart, int sliceEnd) {
|
|
this.trackTexture = texture;
|
|
this.trackSliceStart = sliceStart;
|
|
this.trackSliceEnd = sliceEnd;
|
|
return this;
|
|
}
|
|
|
|
public ScrollBar setOverflowType(OverflowType overflowType) {
|
|
this.overflowType = overflowType;
|
|
return this;
|
|
}
|
|
|
|
public OverflowType getOverflowType() {
|
|
return this.overflowType;
|
|
}
|
|
|
|
public ScrollBar setScrollPlace(ScrollPlace scrollPlace) {
|
|
this.scrollPlace = scrollPlace;
|
|
return this;
|
|
}
|
|
|
|
public ScrollPlace getScrollPlace() {
|
|
return this.scrollPlace;
|
|
}
|
|
|
|
public ScrollBar setScrollType(ScrollType scrollType) {
|
|
this.scrollType = scrollType;
|
|
return this;
|
|
}
|
|
|
|
private int getActualSize(ScrollContainer container) {
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
return container.getActualWidth();
|
|
} else {
|
|
return container.getActualHeight();
|
|
}
|
|
}
|
|
|
|
public int getVisibleSize(ScrollContainer container) {
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
return container.getVisibleWidth();
|
|
} else {
|
|
return container.getVisibleHeight();
|
|
}
|
|
}
|
|
|
|
private int getMaxThumbSize(ScrollContainer container) {
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
return getMaxTrackSize(container) - this.thumbPaddingLeft - this.thumbPaddingRight;
|
|
} else {
|
|
return getMaxTrackSize(container) - this.thumbPaddingTop - this.thumbPaddingBottom;
|
|
}
|
|
}
|
|
|
|
private int getMaxTrackSize(ScrollContainer container) {
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
return container.w - this.trackPaddingLeft - this.trackPaddingRight;
|
|
} else {
|
|
return container.h - this.trackPaddingTop - this.trackPaddingBottom;
|
|
}
|
|
}
|
|
|
|
private int getMinThumbSize() {
|
|
|
|
if (this.thumbTexture != null) {
|
|
return this.scrollType == ScrollType.HORIZONTAL ? this.thumbTexture.getWidth()
|
|
: this.thumbTexture.getHeight();
|
|
}
|
|
|
|
return MINIMUM_THUMB_SIZE;
|
|
}
|
|
|
|
public float getScrollOffset(ScrollContainer container) {
|
|
final float thumbSize = getMaxThumbSize(container) - calculateMainAxisSize(container);
|
|
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
return container.getHorizontalScrollOffset()
|
|
/ (float) (container.getActualWidth() - container.getVisibleWidth())
|
|
* thumbSize;
|
|
} else {
|
|
return container.getVerticalScrollOffset()
|
|
/ (float) (container.getActualHeight() - container.getVisibleHeight())
|
|
* thumbSize;
|
|
}
|
|
}
|
|
|
|
public float calculateMainAxisSize(ScrollContainer container) {
|
|
final int visibleSize = getVisibleSize(container);
|
|
final int actualSize = getActualSize(container);
|
|
final int trackSize = getMaxThumbSize(container);
|
|
|
|
return Math.max(Math.min(trackSize, (trackSize / (float) actualSize) * visibleSize), getMinThumbSize());
|
|
}
|
|
|
|
public Rectangle4i trackBounds(ScrollContainer container) {
|
|
int trackWidth = getTrackWidth();
|
|
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
final int y = this.scrollPlace == ScrollPlace.START ? container.y - trackWidth - this.trackPaddingBottom
|
|
: container.y + container.h + this.trackPaddingTop;
|
|
|
|
return new Rectangle4i(container.x + this.trackPaddingLeft, y, getMaxTrackSize(container), trackWidth);
|
|
|
|
} else {
|
|
final int x = this.scrollPlace == ScrollPlace.START ? container.x - trackWidth - this.trackPaddingRight
|
|
: container.x + container.w + this.trackPaddingLeft;
|
|
|
|
return new Rectangle4i(x, container.y + this.trackPaddingTop, trackWidth, getMaxTrackSize(container));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
public Rectangle4i thumbBounds(ScrollContainer container) {
|
|
final int mainAxisSize = (int) calculateMainAxisSize(container);
|
|
final int offset = (int) Math.ceil(getScrollOffset(container));
|
|
final Rectangle4i bounds = trackBounds(container);
|
|
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
final int y = this.scrollPlace == ScrollPlace.START
|
|
? bounds.y + bounds.h - getThumbWidth() - this.thumbPaddingBottom
|
|
: bounds.y + this.thumbPaddingTop;
|
|
|
|
return new Rectangle4i(
|
|
bounds.x + this.thumbPaddingLeft + offset,
|
|
y,
|
|
mainAxisSize,
|
|
bounds.h - this.thumbPaddingTop - this.thumbPaddingBottom);
|
|
} else {
|
|
final int x = this.scrollPlace == ScrollPlace.START
|
|
? bounds.x + bounds.w - getThumbWidth() - this.thumbPaddingRight
|
|
: bounds.x + this.thumbPaddingLeft;
|
|
|
|
return new Rectangle4i(
|
|
x,
|
|
bounds.y + this.thumbPaddingTop + offset,
|
|
bounds.w - this.thumbPaddingLeft - this.thumbPaddingRight,
|
|
mainAxisSize);
|
|
}
|
|
}
|
|
|
|
public boolean setScrollOffset(ScrollContainer container, int offset) {
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
return container.setHorizontalScrollOffset(offset);
|
|
} else {
|
|
return container.setVerticalScrollOffset(offset);
|
|
}
|
|
}
|
|
|
|
public boolean onClick(ScrollContainer container, int mx, int my, int button) {
|
|
final Rectangle4i bounds = trackBounds(container);
|
|
|
|
if (bounds.contains(mx, my)) {
|
|
final float mainAxisSize = calculateMainAxisSize(container);
|
|
final float thumbSize = getMaxThumbSize(container) - mainAxisSize;
|
|
final Rectangle4i thumbBounds = thumbBounds(container);
|
|
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
final int relativeX = mx - bounds.x - this.thumbPaddingLeft;
|
|
|
|
if (mx < thumbBounds.x || mx > thumbBounds.x + thumbBounds.w) {
|
|
this.handleClickOffset = mainAxisSize / 2;
|
|
} else {
|
|
this.handleClickOffset = mx - thumbBounds.x;
|
|
}
|
|
|
|
final float newOffset = ((relativeX - this.handleClickOffset)
|
|
* (container.getActualWidth() - container.getVisibleWidth())) / thumbSize;
|
|
container.setHorizontalScrollOffset((int) newOffset);
|
|
} else {
|
|
final int relativeY = my - bounds.y - this.thumbPaddingTop;
|
|
|
|
if (my < thumbBounds.y || my > thumbBounds.y + thumbBounds.h) {
|
|
this.handleClickOffset = mainAxisSize / 2f;
|
|
} else {
|
|
this.handleClickOffset = my - thumbBounds.y;
|
|
}
|
|
|
|
final float newOffset = ((relativeY - this.handleClickOffset)
|
|
* (container.getActualHeight() - container.getVisibleHeight())) / thumbSize;
|
|
|
|
container.setVerticalScrollOffset((int) newOffset);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public boolean onMouseDragged(ScrollContainer container, int mx, int my, int buttonId, long heldTime) {
|
|
|
|
if (this.handleClickOffset >= 0) {
|
|
final Rectangle4i bounds = trackBounds(container);
|
|
final float mainAxisSize = calculateMainAxisSize(container);
|
|
final float thumbSize = getMaxThumbSize(container) - mainAxisSize;
|
|
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
final int relativeX = mx - bounds.x - this.thumbPaddingLeft;
|
|
final float newOffset = ((relativeX - this.handleClickOffset)
|
|
* (container.getActualWidth() - container.getVisibleWidth())) / thumbSize;
|
|
container.setHorizontalScrollOffset((int) newOffset);
|
|
} else {
|
|
int relativeY = my - bounds.y - this.thumbPaddingTop;
|
|
final float newOffset = ((relativeY - this.handleClickOffset)
|
|
* (container.getActualHeight() - container.getVisibleHeight())) / thumbSize;
|
|
|
|
container.setVerticalScrollOffset((int) newOffset);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public boolean onClickReleased(ScrollContainer container, int mx, int my, int buttonId) {
|
|
|
|
if (this.handleClickOffset >= 0) {
|
|
this.handleClickOffset = -1;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public boolean isMouseDragged() {
|
|
return this.handleClickOffset >= 0;
|
|
}
|
|
|
|
public void draw(ScrollContainer container, int mx, int my, float opacity) {
|
|
|
|
if (opacity <= 0 && this.overflowType == OverflowType.OVERLAY) {
|
|
return;
|
|
}
|
|
|
|
if (this.overflowType != OverflowType.OVERLAY) {
|
|
opacity = 1;
|
|
}
|
|
|
|
final Rectangle4i trackBounds = trackBounds(container);
|
|
final Rectangle4i thumbBounds = thumbBounds(container);
|
|
final boolean selected = isMouseDragged() || thumbBounds.contains(mx, my);
|
|
final boolean disabled = getVisibleSize(container) >= getActualSize(container);
|
|
|
|
if (this.trackTexture != null) {
|
|
drawTexture(this.trackTexture, this.trackSliceStart, this.trackSliceEnd, trackBounds, false, opacity);
|
|
} else {
|
|
drawTrackRect(container, trackBounds, opacity);
|
|
}
|
|
|
|
if (this.thumbTexture != null) {
|
|
drawTexture(this.thumbTexture, this.thumbSliceStart, this.thumbSliceEnd, thumbBounds, disabled, opacity);
|
|
} else {
|
|
drawThumbRect(container, thumbBounds, selected, opacity);
|
|
}
|
|
}
|
|
|
|
private void drawTrackRect(ScrollContainer container, Rectangle4i bounds, float opacity) {
|
|
final float trackSize = this.trackWidth / 3f;
|
|
final Color trackColor = new Color(
|
|
BACKGROUND_COLOR.getRed(),
|
|
BACKGROUND_COLOR.getGreen(),
|
|
BACKGROUND_COLOR.getBlue(),
|
|
(int) (BACKGROUND_COLOR.getAlpha() * opacity));
|
|
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
NEIClientUtils.drawRect(bounds.x, bounds.y + trackSize, bounds.w, trackSize, trackColor);
|
|
} else {
|
|
NEIClientUtils.drawRect(bounds.x + trackSize, bounds.y, trackSize, bounds.h, trackColor);
|
|
}
|
|
}
|
|
|
|
private void drawThumbRect(ScrollContainer container, Rectangle4i bounds, boolean selected, float opacity) {
|
|
final Color color = selected ? THUMB_SELECTED_COLOR : THUMB_COLOR;
|
|
final Color thumbColor = new Color(
|
|
color.getRed(),
|
|
color.getGreen(),
|
|
color.getBlue(),
|
|
(int) (color.getAlpha() * opacity));
|
|
|
|
NEIClientUtils.drawRect(bounds.x, bounds.y, bounds.w, bounds.h, thumbColor);
|
|
}
|
|
|
|
private void drawTexture(DrawableResource texture, int sliceStart, int sliceEnd, Rectangle4i bounds,
|
|
boolean disabled, float opacity) {
|
|
final float c = disabled ? 0.65f : 1f;
|
|
|
|
GL11.glColor4f(c, c, c, opacity);
|
|
GL11.glEnable(GL11.GL_BLEND);
|
|
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
|
|
|
|
if (this.scrollType == ScrollType.HORIZONTAL) {
|
|
texture.draw(bounds.x, bounds.y, bounds.w, texture.getHeight(), sliceStart, sliceEnd, 0, 0);
|
|
} else {
|
|
texture.draw(bounds.x, bounds.y, texture.getWidth(), bounds.h, 0, 0, sliceStart, sliceEnd);
|
|
}
|
|
|
|
}
|
|
|
|
}
|