mirror of
https://github.com/MinecraftForge/MinecraftForge.git
synced 2026-11-12 16:27:47 +00:00
Add modern implementation of the Slider widget and deprecate the old one (#8496)
This commit is contained in:
1 parent
eed24f017f
commit
f0b90dc35d
2 files changed
+225
No files matched your search
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Minecraft Forge - Forge Development LLC
|
||||
* SPDX-License-Identifier: LGPL-2.1-only
|
||||
*/
|
||||
|
||||
package net.minecraftforge.client.gui.widget;
|
||||
|
||||
import net.minecraft.client.gui.components.AbstractSliderButton;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.util.Mth;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
/**
|
||||
* Slider widget implementation which allows inputting values in a certain range with optional step size.
|
||||
*/
|
||||
public class ForgeSlider extends AbstractSliderButton
|
||||
{
|
||||
protected Component prefix;
|
||||
protected Component suffix;
|
||||
|
||||
protected double minValue;
|
||||
protected double maxValue;
|
||||
|
||||
/** Allows input of discontinuous values with a certain step */
|
||||
protected double stepSize;
|
||||
|
||||
protected boolean drawString;
|
||||
|
||||
private final DecimalFormat format;
|
||||
|
||||
/**
|
||||
* @param x x position of upper left corner
|
||||
* @param y y position of upper left corner
|
||||
* @param width Width of the widget
|
||||
* @param height Height of the widget
|
||||
* @param prefix {@link Component} displayed before the value string
|
||||
* @param suffix {@link Component} displayed after the value string
|
||||
* @param minValue Minimum (left) value of slider
|
||||
* @param maxValue Maximum (right) value of slider
|
||||
* @param currentValue Starting value when widget is first displayed
|
||||
* @param stepSize Size of step used. Precision will automatically be calculated based on this value if this value is not 0.
|
||||
* @param precision Only used when {@code stepSize} is 0. Limited to a maximum of 4 (inclusive).
|
||||
* @param drawString Should text be displayed on the widget
|
||||
*/
|
||||
public ForgeSlider(int x, int y, int width, int height, Component prefix, Component suffix, double minValue, double maxValue, double currentValue, double stepSize, int precision, boolean drawString)
|
||||
{
|
||||
super(x, y, width, height, TextComponent.EMPTY, 0D);
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.minValue = minValue;
|
||||
this.maxValue = maxValue;
|
||||
this.stepSize = Math.abs(stepSize);
|
||||
this.value = this.snapToNearest((currentValue - minValue) / (maxValue - minValue));
|
||||
this.drawString = drawString;
|
||||
|
||||
if (stepSize == 0D)
|
||||
{
|
||||
precision = Math.min(precision, 4);
|
||||
|
||||
StringBuilder builder = new StringBuilder("0");
|
||||
|
||||
if (precision > 0)
|
||||
builder.append('.');
|
||||
|
||||
while (precision-- > 0)
|
||||
builder.append('0');
|
||||
|
||||
this.format = new DecimalFormat(builder.toString());
|
||||
}
|
||||
else if (Mth.equal(this.stepSize, Math.floor(this.stepSize)))
|
||||
{
|
||||
this.format = new DecimalFormat("0");
|
||||
}
|
||||
else
|
||||
{
|
||||
this.format = new DecimalFormat(Double.toString(this.stepSize).replaceAll("\\d", "0"));
|
||||
}
|
||||
|
||||
this.updateMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Overload with {@code stepSize} set to 1, useful for sliders with whole number values.
|
||||
*/
|
||||
public ForgeSlider(int x, int y, int width, int height, Component prefix, Component suffix, double minValue, double maxValue, double currentValue, boolean drawString)
|
||||
{
|
||||
this(x, y, width, height, prefix, suffix, minValue, maxValue, currentValue, 1D, 0, drawString);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current slider value as a double
|
||||
*/
|
||||
public double getValue()
|
||||
{
|
||||
return this.value * (maxValue - minValue) + minValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current slider value as an long
|
||||
*/
|
||||
public long getValueLong()
|
||||
{
|
||||
return Math.round(this.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current slider value as an int
|
||||
*/
|
||||
public int getValueInt()
|
||||
{
|
||||
return (int) this.getValueLong();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value The new slider value
|
||||
*/
|
||||
public void setValue(double value)
|
||||
{
|
||||
this.value = this.snapToNearest((value - this.minValue) / (this.maxValue - this.minValue));
|
||||
this.updateMessage();
|
||||
}
|
||||
|
||||
public String getValueString()
|
||||
{
|
||||
return this.format.format(this.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(double mouseX, double mouseY)
|
||||
{
|
||||
this.setValueFromMouse(mouseX);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDrag(double mouseX, double mouseY, double dragX, double dragY)
|
||||
{
|
||||
super.onDrag(mouseX, mouseY, dragX, dragY);
|
||||
this.setValueFromMouse(mouseX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean keyPressed(int keyCode, int scanCode, int modifiers)
|
||||
{
|
||||
boolean flag = keyCode == GLFW.GLFW_KEY_LEFT;
|
||||
if (flag || keyCode == GLFW.GLFW_KEY_RIGHT)
|
||||
{
|
||||
if (this.minValue > this.maxValue)
|
||||
flag = !flag;
|
||||
float f = flag ? -1F : 1F;
|
||||
if (stepSize <= 0D)
|
||||
this.setSliderValue(this.value + (f / (this.width - 8)));
|
||||
else
|
||||
this.setValue(this.getValue() + f * this.stepSize);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setValueFromMouse(double mouseX)
|
||||
{
|
||||
this.setSliderValue((mouseX - (this.x + 4)) / (this.width - 8));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param value Percentage of slider range
|
||||
*/
|
||||
private void setSliderValue(double value)
|
||||
{
|
||||
double oldValue = this.value;
|
||||
this.value = this.snapToNearest(value);
|
||||
if (!Mth.equal(oldValue, this.value))
|
||||
this.applyValue();
|
||||
|
||||
this.updateMessage();
|
||||
}
|
||||
|
||||
/**
|
||||
* Snaps the value, so that the displayed value is the nearest multiple of {@code stepSize}.
|
||||
* If {@code stepSize} is 0, no snapping occurs.
|
||||
*/
|
||||
private double snapToNearest(double value)
|
||||
{
|
||||
if(stepSize <= 0D)
|
||||
return Mth.clamp(value, 0D, 1D);
|
||||
|
||||
value = Mth.lerp(Mth.clamp(value, 0D, 1D), this.minValue, this.maxValue);
|
||||
|
||||
value = (stepSize * Math.round(value / stepSize));
|
||||
|
||||
if (this.minValue > this.maxValue)
|
||||
{
|
||||
value = Mth.clamp(value, this.maxValue, this.minValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = Mth.clamp(value, this.minValue, this.maxValue);
|
||||
}
|
||||
|
||||
return Mth.map(value, this.minValue, this.maxValue, 0D, 1D);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateMessage()
|
||||
{
|
||||
if (this.drawString)
|
||||
{
|
||||
this.setMessage(new TextComponent("").append(prefix).append(this.getValueString()).append(suffix));
|
||||
}
|
||||
else
|
||||
{
|
||||
this.setMessage(TextComponent.EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyValue() {}
|
||||
}
|
||||
@@ -16,8 +16,13 @@ import javax.annotation.Nullable;
|
||||
/**
|
||||
* This class is blatantly stolen from iChunUtils with permission.
|
||||
*
|
||||
* @deprecated This class has a few issues,
|
||||
* mainly <a href="https://github.com/MinecraftForge/MinecraftForge/issues/8485">MinecraftForge/MinecraftForge#8485</a>.
|
||||
* Use {@link ForgeSlider} instead.
|
||||
*
|
||||
* @author iChun
|
||||
*/
|
||||
@Deprecated(since = "1.18.2", forRemoval = true)
|
||||
public class Slider extends ExtendedButton
|
||||
{
|
||||
/** The value of this slider control. */
|
||||
|
||||
Reference in new issue
Block a user