package gminers.glasspane.component.numeric;
import gminers.glasspane.Direction;
import gminers.glasspane.HorzAlignment;
import gminers.glasspane.VertAlignment;
import gminers.glasspane.component.Focusable;
import gminers.glasspane.component.button.PaneButton;
import gminers.glasspane.component.text.PaneLabel;
import gminers.glasspane.event.StateChangedEvent;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.experimental.FieldDefaults;
import net.minecraft.client.Minecraft;
import org.lwjgl.input.Mouse;
import org.lwjgl.opengl.GL11;
/**
* A PaneSlider implements a Slider, which has a knob that can be moved left&right/up&down to increase/decrease a value.
*
* @author aesen
*
*/
@FieldDefaults(level = AccessLevel.PROTECTED)
@ToString
@Getter
@Setter
public class PaneSlider
extends PaneLabel
implements Focusable {
public PaneSlider() {
setText("Slider");
setWidth(427);
setHeight(20);
setAlignmentX(HorzAlignment.MIDDLE);
setAlignmentY(VertAlignment.MIDDLE);
}
/**
* Whether or not this slider should render as enabled, and should be allowed to be moved and have the focus.
*/
boolean enabled = true;
/**
* The color of this slider's knob. If set to 0xFFFFFF, renders the same as a default Minecraft slider.
*/
int knobColor = 0xFFFFFF;
/**
* The color of the text of this slider when it is disabled.
*/
int disabledColor = 0xA0A0A0;
/**
* The color of the text of this slider when hovering.
*/
int hoveredColor = 0xFFFFA0;
/**
* The current value of this slider.
*/
int value = 0;
/**
* The maximum value of this slider.
*/
int maximum = 16;
/**
* Whether or not to render a solid background on this slider. If set to false, this can be used to make a progress slider
* by putting a slider in front of a progress bar.
*/
boolean renderBackground = true;
/**
* The direction of this slider.
*/
Direction direction = Direction.HORIZONTAL;
/**
* The length to use for the knob. If this slider is vertical, this is height. If it is horizontal, it is width.
*/
int knobLength = 8;
@Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE) private float stretch = 0f;
@Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE) private float stretchTarget = 0f;
@Override
protected void doRender(int mouseX, int mouseY, float partialTicks) {
// determine the u and v offsets we want
final int u = 0;
int v = 40;
final boolean hover = Mouse.isInsideWindow() && withinBounds(mouseX, mouseY);
// bind the widgets file
Minecraft.getMinecraft().renderEngine.bindTexture(RESOURCE);
boolean horz = (direction == Direction.HORIZONTAL);
if (renderBackground) {
GL11.glPushMatrix();
GL11.glColor3f(1.0f, 1.0f, 1.0f);
boolean focus = getParent() != null && getParent().getFocusedComponent() == this;
if (horz) {
PaneButton.renderStretchyTexturedRect(0, 0, u, 0, width, height, 220, 40);
if (focus) {
PaneButton.renderStretchyTexturedRect(0, 0, u, 200, width, height, 220, 40);
}
} else {
GL11.glTranslatef(width / 2f, height / 2f, 0);
GL11.glRotatef(90f, 0, 0, 1.0f);
PaneButton.renderStretchyTexturedRect(-(height / 2), -(width / 2), u, 0, height, width, 220, 40);
if (focus) {
PaneButton.renderStretchyTexturedRect(-(height / 2), -(width / 2), u, 200, height, width, 220, 40);
}
}
GL11.glPopMatrix();
}
// unpack the knob color
int r = knobColor >> 16 & 255;
int g = knobColor >> 8 & 255;
final int b = knobColor & 255;
float mult = (float) value / (float) maximum;
int knobX = 0;
int knobY = 0;
float transX = 0;
float transY = 0;
int knobWidth = 0;
int knobHeight = 0;
int length = horz ? width : height;
int knob = (int) (mult * (length - knobLength));
if (knob > knobLength && knob < (length - knobLength)) {
knob = knob + (knobLength / 2);
}
float trans = stretch * ((length / maximum) / 2f);
if (horz) {
knobX = knob;
transX = trans;
knobWidth = knobLength;
knobHeight = height;
} else {
knobY = knob;
transY = trans;
knobWidth = width;
knobHeight = knobLength;
}
GL11.glPushMatrix();
GL11.glTranslatef(transX, transY, 0f);
GL11.glEnable(GL11.GL_BLEND);
GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA);
GL11.glColor4f(r, g, b, 0.15f);
PaneButton.renderStretchyTexturedRect(knobX, knobY, 0, v, knobWidth, knobHeight, 220, 40);
GL11.glDisable(GL11.GL_BLEND);
GL11.glPopMatrix();
// apply the knob color
GL11.glColor3f(r / 255f, g / 255f, b / 255f);
PaneButton.renderStretchyTexturedRect(knobX, knobY, 0, v, knobWidth, knobHeight, 220, 40);
// change the label's color, if needed
final int trueColor = color;
if (!enabled) {
color = disabledColor;
} else if (hover) {
color = hoveredColor;
}
// render the label
GL11.glTranslatef(0, 0, 0.001f);
super.doRender(mouseX, mouseY, partialTicks);
color = trueColor;
}
@Getter(AccessLevel.NONE) @Setter(AccessLevel.NONE) private boolean down = false;
@Override
protected void doTick() {
if (down) {
if (!enabled || !Mouse.isButtonDown(0)) {
down = false;
return;
}
if (enabled) {
int mouseOfs = (direction == Direction.HORIZONTAL) ? mouseX - getX() : mouseY - getY();
int length = (direction == Direction.HORIZONTAL) ? width : height;
float knobMult = (float) (value) / (float) maximum;
int knobPos = (int) ((knobMult * (length - knobLength)) + (knobLength / 2));
int ofs = mouseOfs - knobPos;
float mult = ((float) mouseOfs / (float) length);
float work = Math.max(0, Math.min((float) mult * (float) maximum, maximum));
int oldValue = value;
if (work < value) {
value = (int) Math.ceil(work);
} else if (work > value) {
value = (int) Math.floor(work);
}
if (oldValue != value) {
fireEvent(StateChangedEvent.class, this);
}
stretchTarget = ofs / ((float) length / (float) maximum);
if (value >= maximum && stretchTarget > 0) {
stretchTarget = 0;
}
if (value <= 0 && stretchTarget < 0) {
stretchTarget = 0;
}
}
stretch = stretch + ((stretchTarget - stretch) / 4f);
} else {
stretch /= 2;
}
}
@Override
protected void mouseWheel(int mouseX, int mouseY, int distance) {
super.mouseWheel(mouseX, mouseY, distance);
if (distance > 0 && value < maximum) {
value++;
fireEvent(StateChangedEvent.class, this);
} else if (distance < 0 && value > 0) {
value--;
fireEvent(StateChangedEvent.class, this);
}
}
@Override
protected void mouseDown(int mouseX, int mouseY, int button) {
super.mouseDown(mouseX, mouseY, button);
if (button == 0) {
down = true;
}
}
}