Files
NotEnoughItems/src/main/java/codechicken/nei/scroll/ScrollContainer.java
T

431 lines
13 KiB
Java

package codechicken.nei.scroll;
import java.awt.Point;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.function.Predicate;
import org.lwjgl.input.Keyboard;
import org.lwjgl.opengl.GL11;
import codechicken.lib.gui.GuiDraw;
import codechicken.lib.vec.Rectangle4i;
import codechicken.nei.NEIClientUtils;
import codechicken.nei.Widget;
import codechicken.nei.WidgetContainer;
import codechicken.nei.scroll.ScrollBar.OverflowType;
import codechicken.nei.scroll.ScrollBar.ScrollType;
public class ScrollContainer extends WidgetContainer {
/** The mouse scroll wheel scroll speed */
protected static final int MOUSE_SCROLL_SPEED = 16;
/** The keyboard arrow keys scroll speed */
protected static final int KEYBOARD_SCROLL_SPEED = 36;
/** The scrollbar will fade away over this many ticks */
protected static final int FADE_TICKS = 24;
protected int xScroll = 0;
protected int yScroll = 0;
protected int actualWidth = 0;
protected int actualHeight = 0;
protected int paddingInlineStart = 0;
protected int paddingInlineEnd = 0;
protected int paddingBlockStart = 0;
protected int paddingBlockEnd = 0;
protected final Map<Widget, Point> relativePosition = new HashMap<>();
protected ScrollBar horizontalScrollBar;
protected ScrollBar verticalScrollBar;
protected int fade = 0;
public Rectangle4i boundsOutside() {
int width = this.w;
int height = this.h;
int x = this.x;
int y = this.y;
if (canScrollVertical() && (this.verticalScrollBar.getOverflowType() == OverflowType.SCROLL
|| this.verticalScrollBar.getOverflowType() == OverflowType.AUTO)) {
final Rectangle4i trackBounds = this.verticalScrollBar.trackBounds(this);
x = Math.min(x, trackBounds.x);
y = Math.min(y, trackBounds.y);
height = Math.max(this.y + height, trackBounds.y + trackBounds.h) - y;
width = Math.max(this.x + width, trackBounds.x + trackBounds.w) - x;
}
if (canScrollHorizontal() && (this.horizontalScrollBar.getOverflowType() == OverflowType.SCROLL
|| this.horizontalScrollBar.getOverflowType() == OverflowType.AUTO)) {
final Rectangle4i trackBounds = this.horizontalScrollBar.trackBounds(this);
x = Math.min(x, trackBounds.x);
y = Math.min(y, trackBounds.y);
height = Math.max(this.y + height, trackBounds.y + trackBounds.h) - y;
width = Math.max(this.x + width, trackBounds.x + trackBounds.w) - x;
}
return new Rectangle4i(x, y, width, height);
}
public Rectangle4i boundsInside() {
return new Rectangle4i(
x + this.paddingInlineStart,
y + this.paddingBlockStart,
getVisibleWidth(),
getVisibleHeight());
}
@Override
public void clear() {
for (Map.Entry<Widget, Point> entry : this.relativePosition.entrySet()) {
entry.getKey().x = entry.getValue().x;
entry.getKey().y = entry.getValue().y;
}
super.clear();
this.relativePosition.clear();
}
@Override
public boolean removeIf(Predicate<Widget> filter) {
final Iterator<Map.Entry<Widget, Point>> it = this.relativePosition.entrySet().iterator();
while (it.hasNext()) {
final Map.Entry<Widget, Point> entry = it.next();
if (filter.test(entry.getKey())) {
entry.getKey().x = entry.getValue().x;
entry.getKey().y = entry.getValue().y;
it.remove();
}
}
return super.removeIf(filter);
}
public void addWidget(Widget widget) {
super.addWidget(widget);
this.relativePosition.put(widget, new Point(widget.x, widget.y));
}
public Point getWidgetPosition(Widget widget) {
return this.relativePosition.get(widget);
}
public void setPaddingInline(int start, int end) {
this.paddingInlineStart = start;
this.paddingInlineEnd = end;
}
public void setPaddingBlock(int start, int end) {
this.paddingBlockStart = start;
this.paddingBlockEnd = end;
}
public int getVisibleWidth() {
return this.w - this.paddingInlineStart - this.paddingInlineEnd;
}
public int getActualWidth() {
return this.actualWidth;
}
public boolean setHorizontalScrollOffset(int offset) {
if (!canScrollHorizontal() && getVisibleWidth() < getActualWidth()) {
offset = 0;
}
final int scroll = this.xScroll;
this.xScroll = Math.max(0, Math.min(getActualWidth() - getVisibleWidth(), offset));
if (scroll != this.xScroll) {
for (Widget widget : this.widgets) {
widget.x += scroll - this.xScroll;
}
this.fade = FADE_TICKS;
return true;
}
return false;
}
public int getHorizontalScrollOffset() {
return this.xScroll;
}
public boolean canScrollHorizontal() {
return this.horizontalScrollBar != null && (this.horizontalScrollBar.getOverflowType() != OverflowType.NONE
&& getVisibleWidth() < getActualWidth()
|| this.horizontalScrollBar.getOverflowType() == OverflowType.SCROLL);
}
public ScrollBar getHorizontalScroll() {
return this.horizontalScrollBar;
}
public ScrollContainer setHorizontalScroll() {
return setHorizontalScroll(ScrollBar.defaultScrollBar());
}
public ScrollContainer setHorizontalScroll(ScrollBar scrollBar) {
this.horizontalScrollBar = scrollBar;
if (this.horizontalScrollBar != null) {
this.horizontalScrollBar.setScrollType(ScrollType.HORIZONTAL);
}
return this;
}
public int getVisibleHeight() {
return this.h - this.paddingBlockStart - this.paddingBlockEnd;
}
public int getActualHeight() {
return this.actualHeight;
}
public boolean setVerticalScrollOffset(int offset) {
if (!canScrollVertical() && getVisibleHeight() < getActualHeight()) {
offset = 0;
}
final int scroll = this.yScroll;
this.yScroll = Math.max(0, Math.min(getActualHeight() - getVisibleHeight(), offset));
if (scroll != this.yScroll) {
for (Widget widget : this.widgets) {
widget.y += scroll - this.yScroll;
}
this.fade = FADE_TICKS;
return true;
}
return false;
}
public int getVerticalScrollOffset() {
return this.yScroll;
}
public boolean canScrollVertical() {
return this.verticalScrollBar != null && (this.verticalScrollBar.getOverflowType() != OverflowType.NONE
&& getVisibleHeight() < getActualHeight()
|| this.verticalScrollBar.getOverflowType() == OverflowType.SCROLL);
}
public ScrollBar getVerticalScroll() {
return this.verticalScrollBar;
}
public ScrollContainer setVerticalScroll() {
return setVerticalScroll(ScrollBar.defaultScrollBar());
}
public ScrollContainer setVerticalScroll(ScrollBar scrollBar) {
this.verticalScrollBar = scrollBar;
if (this.verticalScrollBar != null) {
this.verticalScrollBar.setScrollType(ScrollType.VERTICAL);
}
return this;
}
@Override
public void draw(int mousex, int mousey) {
final boolean canScrollVertical = canScrollVertical();
final boolean canScrollHorizontal = canScrollHorizontal();
if (canScrollVertical || canScrollHorizontal) {
GuiHelper.useScissor(
this.x + this.paddingInlineStart,
this.y + this.paddingBlockStart,
this.w - this.paddingInlineStart - this.paddingInlineEnd,
this.h - this.paddingBlockStart - this.paddingBlockEnd,
() -> drawContent(mousex, mousey));
GL11.glPushAttrib(GL11.GL_ENABLE_BIT | GL11.GL_COLOR_BUFFER_BIT | GL11.GL_LIGHTING_BIT);
if (canScrollVertical) {
this.verticalScrollBar.draw(this, mousex, mousey, getScrollBarOpacity());
}
if (canScrollHorizontal) {
this.horizontalScrollBar.draw(this, mousex, mousey, getScrollBarOpacity());
}
GL11.glPopAttrib();
} else {
drawContent(mousex, mousey);
}
}
protected void drawContent(int mousex, int mousey) {
GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
GL11.glPushMatrix();
GL11.glColor4f(1, 1, 1, 1);
super.draw(mousex, mousey);
GL11.glPopMatrix();
GL11.glPopAttrib();
}
private float getScrollBarOpacity() {
return Math.min(2f * this.fade, FADE_TICKS) / FADE_TICKS;
}
@Override
public void update() {
this.actualHeight = 0;
this.actualWidth = 0;
for (Map.Entry<Widget, Point> entry : this.relativePosition.entrySet()) {
entry.getKey().x = entry.getValue().x;
entry.getKey().y = entry.getValue().y;
}
super.update();
final int x = this.x + this.paddingInlineStart - this.xScroll;
final int y = this.y + this.paddingBlockStart - this.yScroll;
for (Widget widget : this.widgets) {
this.actualWidth = Math.max(this.actualWidth, widget.x + widget.w);
this.actualHeight = Math.max(this.actualHeight, widget.y + widget.h);
widget.x += x;
widget.y += y;
}
if (this.fade > 0) {
final Point mouse = GuiDraw.getMousePosition();
if (canScrollVertical() && (this.verticalScrollBar.isMouseDragged()
|| this.verticalScrollBar.trackBounds(this).contains(mouse.x, mouse.y))) {
this.fade = FADE_TICKS;
} else if (canScrollHorizontal() && (this.horizontalScrollBar.isMouseDragged()
|| this.horizontalScrollBar.trackBounds(this).contains(mouse.x, mouse.y))) {
this.fade = FADE_TICKS;
} else {
this.fade--;
}
}
setHorizontalScrollOffset(this.xScroll);
setVerticalScrollOffset(this.yScroll);
}
@Override
public boolean onMouseWheel(int direction, int mousex, int mousey) {
if (super.onMouseWheel(direction, mousex, mousey)) {
return true;
}
if (boundsOutside().contains(mousex, mousey)) {
if (canScrollHorizontal() && (NEIClientUtils.shiftKey()
|| this.horizontalScrollBar.trackBounds(this).contains(mousex, mousey))) {
this.horizontalScrollBar.setScrollOffset(this, this.xScroll - direction * MOUSE_SCROLL_SPEED);
return true;
}
if (canScrollVertical()) {
this.verticalScrollBar.setScrollOffset(this, this.yScroll - direction * MOUSE_SCROLL_SPEED);
return true;
}
}
return false;
}
@Override
public boolean handleClick(int mousex, int mousey, int button) {
if (canScrollVertical() && this.verticalScrollBar.onClick(this, mousex, mousey, button)) {
return true;
}
if (canScrollHorizontal() && this.horizontalScrollBar.onClick(this, mousex, mousey, button)) {
return true;
}
if (super.handleClick(mousex, mousey, button)) {
return true;
}
return false;
}
@Override
public void mouseDragged(int mousex, int mousey, int button, long heldTime) {
if (canScrollVertical() && this.verticalScrollBar.onMouseDragged(this, mousex, mousey, button, heldTime)) {
return;
}
if (canScrollHorizontal() && this.horizontalScrollBar.onMouseDragged(this, mousex, mousey, button, heldTime)) {
return;
}
super.mouseDragged(mousex, mousey, button, heldTime);
}
@Override
public void mouseUp(int mousex, int mousey, int button) {
if (canScrollVertical()) {
this.verticalScrollBar.onClickReleased(this, mousex, mousey, button);
}
if (canScrollHorizontal()) {
this.horizontalScrollBar.onClickReleased(this, mousex, mousey, button);
}
super.mouseUp(mousex, mousey, button);
}
@Override
public boolean handleKeyPress(int keyCode, char keyChar) {
if (super.handleKeyPress(keyCode, keyChar)) {
return true;
}
if (this.isFocused()) {
switch (keyCode) {
case Keyboard.KEY_UP:
return canScrollVertical()
&& this.verticalScrollBar.setScrollOffset(this, this.yScroll - KEYBOARD_SCROLL_SPEED);
case Keyboard.KEY_DOWN:
return canScrollVertical()
&& this.verticalScrollBar.setScrollOffset(this, this.yScroll + KEYBOARD_SCROLL_SPEED);
case Keyboard.KEY_LEFT:
return canScrollHorizontal()
&& this.horizontalScrollBar.setScrollOffset(this, this.xScroll - KEYBOARD_SCROLL_SPEED);
case Keyboard.KEY_RIGHT:
return canScrollHorizontal()
&& this.horizontalScrollBar.setScrollOffset(this, this.xScroll + KEYBOARD_SCROLL_SPEED);
}
}
return false;
}
}